├── .gitignore ├── .idea ├── .gitignore ├── compiler.xml ├── encodings.xml ├── jarRepositories.xml ├── libraries │ └── mybatis_generator_for_imooc_1_0_SNAPSHOT.xml ├── misc.xml └── uiDesigner.xml ├── README.md ├── book-api ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── imooc │ │ ├── Application.java │ │ ├── config │ │ ├── InterceptorConfig.java │ │ ├── MinIOConfig.java │ │ └── knife4jConfig.java │ │ ├── controller │ │ ├── BaseController.java │ │ ├── BaseInfoProperties.java │ │ ├── CommentController.java │ │ ├── FansController.java │ │ ├── FileController.java │ │ ├── MsgController.java │ │ ├── PassportController.java │ │ ├── RabbitMQConsumer.java │ │ ├── UserInfoController.java │ │ └── VlogController.java │ │ └── intercepter │ │ ├── PassportInterceptor.java │ │ └── UserTokenInterceptor.java │ └── resources │ ├── application-dev.yml │ ├── application-prod.yml │ ├── application.yml │ ├── banner │ ├── banner.txt │ ├── cat.png │ └── qiaoba.txt │ └── bootstrap.yml ├── book-common ├── pom.xml └── src │ └── main │ ├── java │ ├── com │ │ └── imooc │ │ │ ├── enums │ │ │ ├── FileTypeEnum.java │ │ │ ├── MessageEnum.java │ │ │ ├── Sex.java │ │ │ ├── UserInfoModifyType.java │ │ │ └── YesOrNo.java │ │ │ ├── exceptions │ │ │ ├── GraceException.java │ │ │ ├── GraceExceptionHandler.java │ │ │ └── MyCustomException.java │ │ │ ├── grace │ │ │ └── result │ │ │ │ ├── GraceJSONResult.java │ │ │ │ ├── IMOOCJSONResult.java │ │ │ │ └── ResponseStatusEnum.java │ │ │ └── utils │ │ │ ├── DateUtil.java │ │ │ ├── DesensitizationUtil.java │ │ │ ├── IPUtil.java │ │ │ ├── JsonUtils.java │ │ │ ├── MinIOUtils.java │ │ │ ├── MyInfo.java │ │ │ ├── PagedGridResult.java │ │ │ ├── RedisOperator.java │ │ │ ├── SMSUtils.java │ │ │ └── TencentCloudProperties.java │ └── org │ │ └── n3r │ │ └── idworker │ │ ├── Code.java │ │ ├── DayCode.java │ │ ├── Id.java │ │ ├── IdWorker.java │ │ ├── InvalidSystemClock.java │ │ ├── RandomCodeStrategy.java │ │ ├── Sid.java │ │ ├── Test.java │ │ ├── WorkerIdStrategy.java │ │ ├── strategy │ │ ├── DayPrefixRandomCodeStrategy.java │ │ ├── DefaultRandomCodeStrategy.java │ │ ├── DefaultWorkerIdStrategy.java │ │ └── FileLock.java │ │ └── utils │ │ ├── HttpReq.java │ │ ├── IPv4Utils.java │ │ ├── Ip.java │ │ ├── Props.java │ │ ├── Serializes.java │ │ └── Utils.java │ └── resources │ └── tencentcloud.properties ├── book-mapper ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── imooc │ │ ├── mapper │ │ ├── CommentMapper.java │ │ ├── CommentMapperCustom.java │ │ ├── FansMapper.java │ │ ├── FansMapperCustom.java │ │ ├── MyLikedVlogMapper.java │ │ ├── UsersMapper.java │ │ ├── VlogMapper.java │ │ └── VlogMapperCustom.java │ │ ├── my │ │ └── mapper │ │ │ └── MyMapper.java │ │ └── repository │ │ └── MessageRepository.java │ └── resources │ └── mapper │ ├── CommentMapper.xml │ ├── CommentMapperCustom.xml │ ├── FansMapper.xml │ ├── FansMapperCustom.xml │ ├── MyLikedVlogMapper.xml │ ├── UsersMapper.xml │ ├── VlogMapper.xml │ └── VlogMapperCustom.xml ├── book-model ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── imooc │ ├── bo │ ├── CommentBO.java │ ├── RegistLoginBO.java │ ├── UpdatedUserBO.java │ └── VlogBO.java │ ├── mo │ └── MessageMO.java │ ├── pojo │ ├── Comment.java │ ├── Fans.java │ ├── MyLikedVlog.java │ ├── Users.java │ └── Vlog.java │ └── vo │ ├── CommentVO.java │ ├── FansVO.java │ ├── IndexVlogVO.java │ ├── UsersVO.java │ └── VlogerVO.java ├── book-service ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── imooc │ ├── base │ ├── BaseInfoProperties.java │ └── RabbitMQConfig.java │ └── service │ ├── CommentService.java │ ├── FansService.java │ ├── MsgService.java │ ├── UserService.java │ ├── VlogService.java │ └── impl │ ├── CommentServiceImpl.java │ ├── FansServiceImpl.java │ ├── MsgServiceImpl.java │ ├── UserServiceImpl.java │ └── VlogServiceImpl.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # 项目排除路径 2 | /book-api/target/ 3 | /book-common/target/ 4 | /book-mapper/target/ 5 | /book-model/target/ 6 | /book-service/target/ -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # 默认忽略的文件 2 | /shelf/ 3 | /workspace.xml 4 | # 基于编辑器的 HTTP 客户端请求 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 31 | 32 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/libraries/mybatis_generator_for_imooc_1_0_SNAPSHOT.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Haut短视频 2 | ## Haut短视频是一个短视频类的App,拥有用户业务模块,短视频模块,粉丝业务模块,评论业务模块,消息业务模块,并且完整上线运行 3 | SpringBoot+Uniapp仿抖音短视频App 4 | 需要前端uinapp可以私信 5 | 6 | 只用修改api模块下面的配置即可运行 7 | 8 | Knife4j 接口文档通过访问 http://ip+prot/doc.html#/home 查看api 9 | # 架构 10 | ![image](https://github.com/vercen/douyin_dome/assets/70558042/460d308a-0b6b-4918-a443-d2a6bf77e2dd) 11 | ![image](https://github.com/vercen/douyin_dome/assets/70558042/50b63912-39b0-4095-8c94-a731f59cb78b) 12 | 13 | # 效果 14 | 15 | ![Screenshot_2023-06-01-11-51-48-628_uni UNI800FF13](https://github.com/vercen/douyin_dome/assets/70558042/60a656c8-6492-4d23-b569-7c8810ba507b) 16 | ![Screenshot_2023-06-01-11-52-17-198_uni UNI800FF13](https://github.com/vercen/douyin_dome/assets/70558042/63656269-ab10-4064-9b43-0e703a3d70b5) 17 | ![Screenshot_2023-06-01-11-52-20-875_uni UNI800FF13](https://github.com/vercen/douyin_dome/assets/70558042/9bd20a3c-2774-4a21-b0c1-b8a4945e2273) 18 | ![Screenshot_2023-06-01-11-52-24-302_uni UNI800FF13](https://github.com/vercen/douyin_dome/assets/70558042/118a8284-a64b-48f9-9caa-47308ec1c532) 19 | -------------------------------------------------------------------------------- /book-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.imooc 8 | imooc-red-book-dev 9 | 1.0-SNAPSHOT 10 | 11 | 12 | jar 13 | 14 | 15 | book-api 16 | 17 | 18 | 8 19 | 8 20 | UTF-8 21 | 22 | 23 | 24 | 25 | 26 | 27 | com.alibaba.cloud 28 | spring-cloud-starter-alibaba-nacos-discovery 29 | 30 | 31 | 32 | 33 | com.alibaba.cloud 34 | spring-cloud-starter-alibaba-nacos-config 35 | 36 | 37 | 38 | 39 | org.springframework.cloud 40 | spring-cloud-starter-bootstrap 41 | 42 | 43 | 44 | 45 | com.imooc 46 | book-service 47 | 1.0-SNAPSHOT 48 | 49 | 50 | com.github.xiaoymin 51 | knife4j-spring-boot-starter 52 | 53 | 54 | com.github.xiaoymin 55 | knife4j-springdoc-ui 56 | 57 | 58 | 59 | 60 | ${project.artifactId} 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-maven-plugin 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/Application.java: -------------------------------------------------------------------------------- 1 | package com.imooc; 2 | 3 | 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.context.annotation.ComponentScan; 7 | import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; 8 | import tk.mybatis.spring.annotation.MapperScan; 9 | 10 | /** 11 | * @author vercen 12 | * @version 1.0 13 | * @date 2023/5/20 14:25 14 | */ 15 | @SpringBootApplication 16 | @MapperScan(basePackages = {"com.imooc.mapper"}) 17 | @ComponentScan(basePackages = {"com.imooc","org.n3r.idworker"}) 18 | @EnableMongoRepositories 19 | public class Application { 20 | public static void main(String[] args) { 21 | SpringApplication.run(Application.class, args); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/config/InterceptorConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.config; 2 | 3 | import com.imooc.intercepter.PassportInterceptor; 4 | import com.imooc.intercepter.UserTokenInterceptor; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 9 | 10 | @Configuration 11 | public class InterceptorConfig implements WebMvcConfigurer { 12 | 13 | @Bean 14 | public PassportInterceptor passportInterceptor() { 15 | return new PassportInterceptor(); 16 | } 17 | 18 | @Bean 19 | public UserTokenInterceptor userTokenInterceptor() { 20 | return new UserTokenInterceptor(); 21 | } 22 | 23 | @Override 24 | public void addInterceptors(InterceptorRegistry registry) { 25 | registry.addInterceptor(passportInterceptor()) 26 | .addPathPatterns("/passport/getSMSCode"); 27 | 28 | registry.addInterceptor(userTokenInterceptor()) 29 | .addPathPatterns("/userInfo/modifyUserInfo") 30 | .addPathPatterns("/userInfo/modifyImage"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/config/MinIOConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.config; 2 | 3 | import com.imooc.utils.MinIOUtils; 4 | import lombok.Data; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | @Data 11 | public class MinIOConfig { 12 | 13 | @Value("${minio.endpoint}") 14 | private String endpoint; 15 | @Value("${minio.fileHost}") 16 | private String fileHost; 17 | @Value("${minio.bucketName}") 18 | private String bucketName; 19 | @Value("${minio.accessKey}") 20 | private String accessKey; 21 | @Value("${minio.secretKey}") 22 | private String secretKey; 23 | 24 | @Value("${minio.imgSize}") 25 | private Integer imgSize; 26 | @Value("${minio.fileSize}") 27 | private Integer fileSize; 28 | 29 | @Bean 30 | public MinIOUtils creatMinioClient() { 31 | return new MinIOUtils(endpoint, bucketName, accessKey, secretKey, imgSize, fileSize); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/config/knife4jConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import springfox.documentation.builders.ApiInfoBuilder; 6 | import springfox.documentation.builders.PathSelectors; 7 | import springfox.documentation.builders.RequestHandlerSelectors; 8 | import springfox.documentation.service.Contact; 9 | import springfox.documentation.spi.DocumentationType; 10 | import springfox.documentation.spring.web.plugins.Docket; 11 | import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; 12 | 13 | /** 14 | * @author vercen 15 | * @version 1.0 16 | * @date 2023/5/20 19:55 17 | */ 18 | @Configuration 19 | @EnableSwagger2WebMvc 20 | public class knife4jConfig { 21 | @Bean 22 | public Docket defaultApi2() { 23 | Docket docket=new Docket(DocumentationType.SWAGGER_2) 24 | .apiInfo(new ApiInfoBuilder() 25 | //.title("swagger-bootstrap-ui-demo RESTful APIs") 26 | .description("短视频实战接口文档") 27 | .termsOfServiceUrl("http://www.xx.com/") 28 | .contact(new Contact("lee", "http://www.imooc.com/", "abc@imooc.com")) 29 | .version("1.0") 30 | .build()) 31 | //分组名称 32 | .groupName("2.X版本") 33 | .select() 34 | //这里指定Controller扫描包路径 35 | .apis(RequestHandlerSelectors.basePackage("com.imooc.controller")) 36 | .paths(PathSelectors.any()) 37 | .build(); 38 | return docket; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/controller/BaseController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.controller; 2 | 3 | import com.imooc.utils.RedisOperator; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | 6 | //public class BaseController { 7 | // 8 | // @Autowired 9 | // public RedisOperator redis; 10 | // 11 | // public static final String MOBILE_SMSCODE = "mobile:smscode"; 12 | // public static final String REDIS_USER_TOKEN = "redis_user_token"; 13 | // public static final String REDIS_USER_INFO = "redis_user_info"; 14 | // 15 | //} 16 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/controller/BaseInfoProperties.java: -------------------------------------------------------------------------------- 1 | //package com.imooc.controller; 2 | // 3 | //import com.github.pagehelper.PageInfo; 4 | //import com.imooc.utils.RedisOperator; 5 | //import org.springframework.beans.factory.annotation.Autowired; 6 | //import org.springframework.validation.BindingResult; 7 | //import org.springframework.validation.FieldError; 8 | // 9 | //import java.util.HashMap; 10 | //import java.util.List; 11 | //import java.util.Map; 12 | // 13 | //public class BaseInfoProperties { 14 | // 15 | // @Autowired 16 | // public RedisOperator redis; 17 | // 18 | // public static final Integer COMMON_START_PAGE = 1; 19 | // public static final Integer COMMON_PAGE_SIZE = 10; 20 | // 21 | // public static final String MOBILE_SMSCODE = "mobile:smscode"; 22 | // public static final String REDIS_USER_TOKEN = "redis_user_token"; 23 | // public static final String REDIS_USER_INFO = "redis_user_info"; 24 | // 25 | // 26 | // //我的关注总数 27 | // public static final String REDIS_MY_FOLLOWS_COUNTS = "redis_my_follows_counts"; 28 | // // 我的粉丝总数 29 | // public static final String REDIS_MY_FANS_COUNTS = "redis_my_fans_counts"; 30 | // 31 | // // 视频和发布者获赞数 32 | // public static final String REDIS_VLOG_BE_LIKED_COUNTS = "redis_vlog_be_liked_counts"; 33 | // public static final String REDIS_VLOGER_BE_LIKED_COUNTS = "redis_vloger_be_liked_counts"; 34 | // 35 | // public PagedGridResult setterPagedGrid(List list, 36 | // Integer page) { 37 | // PageInfo pageList = new PageInfo<>(list); 38 | // PagedGridResult gridResult = new PagedGridResult(); 39 | // gridResult.setRows(list); 40 | // gridResult.setPage(page); 41 | // gridResult.setRecords(pageList.getTotal()); 42 | // gridResult.setTotal(pageList.getPages()); 43 | // return gridResult; 44 | // } 45 | // 46 | //} 47 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/controller/CommentController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.controller; 2 | 3 | import com.imooc.base.BaseInfoProperties; 4 | import com.imooc.bo.CommentBO; 5 | import com.imooc.enums.MessageEnum; 6 | import com.imooc.grace.result.GraceJSONResult; 7 | import com.imooc.pojo.Comment; 8 | import com.imooc.pojo.Vlog; 9 | import com.imooc.service.CommentService; 10 | import com.imooc.service.MsgService; 11 | import com.imooc.service.VlogService; 12 | import com.imooc.vo.CommentVO; 13 | import io.swagger.annotations.Api; 14 | import lombok.extern.slf4j.Slf4j; 15 | import org.apache.commons.lang3.StringUtils; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.web.bind.annotation.*; 18 | 19 | import javax.validation.Valid; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | @Slf4j 24 | @Api(tags = "CommentController 评论模块的接口") 25 | @RequestMapping("comment") 26 | @RestController 27 | public class CommentController extends BaseInfoProperties { 28 | 29 | @Autowired 30 | private CommentService commentService; 31 | @Autowired 32 | private MsgService msgService; 33 | @Autowired 34 | private VlogService vlogService; 35 | // 36 | @PostMapping("create") 37 | public GraceJSONResult create(@RequestBody @Valid CommentBO commentBO) 38 | throws Exception { 39 | 40 | CommentVO commentVO = commentService.createComment(commentBO); 41 | return GraceJSONResult.ok(commentVO); 42 | } 43 | // 44 | @GetMapping("counts") 45 | public GraceJSONResult counts(@RequestParam String vlogId) { 46 | 47 | String countsStr = redis.get(REDIS_VLOG_COMMENT_COUNTS + ":" + vlogId); 48 | if (StringUtils.isBlank(countsStr)) { 49 | countsStr = "0"; 50 | } 51 | 52 | return GraceJSONResult.ok(Integer.valueOf(countsStr)); 53 | } 54 | 55 | @GetMapping("list") 56 | public GraceJSONResult list(@RequestParam String vlogId, 57 | @RequestParam(defaultValue = "") String userId, 58 | @RequestParam Integer page, 59 | @RequestParam Integer pageSize) { 60 | 61 | return GraceJSONResult.ok( 62 | commentService.queryVlogComments( 63 | vlogId, 64 | userId, 65 | page, 66 | pageSize)); 67 | } 68 | 69 | @DeleteMapping("delete") 70 | public GraceJSONResult delete(@RequestParam String commentUserId, 71 | @RequestParam String commentId, 72 | @RequestParam String vlogId) { 73 | commentService.deleteComment(commentUserId, 74 | commentId, 75 | vlogId); 76 | return GraceJSONResult.ok(); 77 | } 78 | 79 | @PostMapping("like") 80 | public GraceJSONResult like(@RequestParam String commentId, 81 | @RequestParam String userId) { 82 | 83 | // 故意犯错,bigkey 84 | redis.incrementHash(REDIS_VLOG_COMMENT_LIKED_COUNTS, commentId, 1); 85 | redis.setHashValue(REDIS_USER_LIKE_COMMENT, userId + ":" + commentId, "1"); 86 | // redis.hset(REDIS_USER_LIKE_COMMENT, userId, "1"); 87 | 88 | 89 | // 系统消息:点赞评论 90 | Comment comment = commentService.getComment(commentId); 91 | Vlog vlog = vlogService.getVlog(comment.getVlogId()); 92 | Map msgContent = new HashMap(); 93 | msgContent.put("vlogId", vlog.getId()); 94 | msgContent.put("vlogCover", vlog.getCover()); 95 | msgContent.put("commentId", commentId); 96 | msgService.createMsg(userId, 97 | comment.getCommentUserId(), 98 | MessageEnum.LIKE_COMMENT.type, 99 | msgContent); 100 | 101 | 102 | return GraceJSONResult.ok(); 103 | } 104 | 105 | @PostMapping("unlike") 106 | public GraceJSONResult unlike(@RequestParam String commentId, 107 | @RequestParam String userId) { 108 | 109 | redis.decrementHash(REDIS_VLOG_COMMENT_LIKED_COUNTS, commentId, 1); 110 | redis.hdel(REDIS_USER_LIKE_COMMENT, userId + ":" + commentId); 111 | 112 | return GraceJSONResult.ok(); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/controller/FansController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.controller; 2 | 3 | import com.imooc.base.BaseInfoProperties; 4 | import com.imooc.grace.result.GraceJSONResult; 5 | import com.imooc.grace.result.ResponseStatusEnum; 6 | import com.imooc.pojo.Users; 7 | import com.imooc.service.FansService; 8 | import com.imooc.service.UserService; 9 | import io.swagger.annotations.Api; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.apache.commons.lang3.StringUtils; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | @Slf4j 16 | @Api(tags = "FansController 粉丝相关业务功能的接口") 17 | @RequestMapping("fans") 18 | @RestController 19 | public class FansController extends BaseInfoProperties { 20 | 21 | @Autowired 22 | private UserService userService; 23 | @Autowired 24 | private FansService fansService; 25 | 26 | @PostMapping("follow") 27 | public GraceJSONResult follow(@RequestParam String myId, 28 | @RequestParam String vlogerId) { 29 | 30 | // 判断两个id不能为空 31 | if (StringUtils.isBlank(myId) || StringUtils.isBlank(vlogerId)) { 32 | return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_ERROR); 33 | } 34 | 35 | // 判断当前用户,自己不能关注自己 36 | if (myId.equalsIgnoreCase(vlogerId)) { 37 | return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_RESPONSE_NO_INFO); 38 | } 39 | 40 | // 判断两个id对应的用户是否存在 41 | Users vloger = userService.getUser(vlogerId); 42 | Users myInfo = userService.getUser(myId); 43 | 44 | // fixme: 两个用户id的数据库查询后的判断,是分开好?还是合并判断好? 45 | if (myInfo == null || vloger == null) { 46 | return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_RESPONSE_NO_INFO); 47 | } 48 | // 49 | // 保存粉丝关系到数据库 50 | fansService.doFollow(myId, vlogerId); 51 | 52 | // 博主的粉丝+1,我的关注+1 53 | redis.increment(REDIS_MY_FOLLOWS_COUNTS + ":" + myId, 1); 54 | redis.increment(REDIS_MY_FANS_COUNTS + ":" + vlogerId, 1); 55 | 56 | // 我和博主的关联关系,依赖redis,不要存储数据库,避免db的性能瓶颈 57 | redis.set(REDIS_FANS_AND_VLOGGER_RELATIONSHIP + ":" + myId + ":" + vlogerId, "1"); 58 | // 59 | return GraceJSONResult.ok(); 60 | } 61 | 62 | @PostMapping("cancel") 63 | public GraceJSONResult cancel(@RequestParam String myId, 64 | @RequestParam String vlogerId) { 65 | 66 | // 删除业务的执行 67 | fansService.doCancel(myId, vlogerId); 68 | 69 | // 博主的粉丝-1,我的关注-1 70 | redis.decrement(REDIS_MY_FOLLOWS_COUNTS + ":" + myId, 1); 71 | redis.decrement(REDIS_MY_FANS_COUNTS + ":" + vlogerId, 1); 72 | 73 | // 我和博主的关联关系,依赖redis,不要存储数据库,避免db的性能瓶颈 74 | redis.del(REDIS_FANS_AND_VLOGGER_RELATIONSHIP + ":" + myId + ":" + vlogerId); 75 | 76 | return GraceJSONResult.ok(); 77 | } 78 | 79 | @GetMapping("queryDoIFollowVloger") 80 | public GraceJSONResult queryDoIFollowVloger(@RequestParam String myId, 81 | @RequestParam String vlogerId) { 82 | return GraceJSONResult.ok(fansService.queryDoIFollowVloger(myId, vlogerId)); 83 | } 84 | 85 | @GetMapping("queryMyFollows") 86 | public GraceJSONResult queryMyFollows(@RequestParam String myId, 87 | @RequestParam Integer page, 88 | @RequestParam Integer pageSize) { 89 | return GraceJSONResult.ok( 90 | fansService.queryMyFollows( 91 | myId, 92 | page, 93 | pageSize)); 94 | } 95 | 96 | @GetMapping("queryMyFans") 97 | public GraceJSONResult queryMyFans(@RequestParam String myId, 98 | @RequestParam Integer page, 99 | @RequestParam Integer pageSize) { 100 | return GraceJSONResult.ok( 101 | fansService.queryMyFans( 102 | myId, 103 | page, 104 | pageSize)); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/controller/FileController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.controller; 2 | 3 | 4 | import com.imooc.config.MinIOConfig; 5 | import com.imooc.grace.result.GraceJSONResult; 6 | import com.imooc.utils.MinIOUtils; 7 | import com.imooc.utils.SMSUtils; 8 | import io.swagger.annotations.Api; 9 | import io.swagger.annotations.ApiOperation; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PostMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | import org.springframework.web.multipart.MultipartFile; 16 | 17 | @Slf4j 18 | @Api(tags = "FileController 文件上传测试的接口") 19 | @RestController 20 | public class FileController { 21 | 22 | @Autowired 23 | private MinIOConfig minIOConfig; 24 | 25 | @PostMapping("upload") 26 | public GraceJSONResult upload(MultipartFile file) throws Exception { 27 | 28 | String fileName = file.getOriginalFilename(); 29 | 30 | MinIOUtils.uploadFile(minIOConfig.getBucketName(), 31 | fileName, 32 | file.getInputStream()); 33 | 34 | String imgUrl = minIOConfig.getFileHost() 35 | + "/" 36 | + minIOConfig.getBucketName() 37 | + "/" 38 | + fileName; 39 | 40 | return GraceJSONResult.ok(imgUrl); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/controller/MsgController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.controller; 2 | 3 | import com.imooc.base.BaseInfoProperties; 4 | import com.imooc.grace.result.GraceJSONResult; 5 | import com.imooc.mo.MessageMO; 6 | import com.imooc.service.MsgService; 7 | import io.swagger.annotations.Api; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RequestParam; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import java.util.List; 16 | 17 | @Slf4j 18 | @Api(tags = "MsgController 消息功能模块的接口") 19 | @RequestMapping("msg") 20 | @RestController 21 | public class MsgController extends BaseInfoProperties { 22 | 23 | @Autowired 24 | private MsgService msgService; 25 | 26 | @GetMapping("list") 27 | public GraceJSONResult list(@RequestParam String userId, 28 | @RequestParam Integer page, 29 | @RequestParam Integer pageSize) { 30 | 31 | // mongodb 从0分页,区别于数据库 32 | if (page == null) { 33 | page = COMMON_START_PAGE_ZERO; 34 | } 35 | if (pageSize == null) { 36 | pageSize = COMMON_PAGE_SIZE; 37 | } 38 | 39 | List list = msgService.queryList(userId, page, pageSize); 40 | 41 | return GraceJSONResult.ok(list); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/controller/PassportController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.controller; 2 | 3 | import com.imooc.base.BaseInfoProperties; 4 | import com.imooc.bo.RegistLoginBO; 5 | import com.imooc.grace.result.GraceJSONResult; 6 | import com.imooc.grace.result.ResponseStatusEnum; 7 | import com.imooc.pojo.Users; 8 | import com.imooc.service.UserService; 9 | import com.imooc.utils.IPUtil; 10 | import com.imooc.utils.SMSUtils; 11 | import com.imooc.vo.UsersVO; 12 | import io.swagger.annotations.Api; 13 | import lombok.extern.slf4j.Slf4j; 14 | import org.apache.commons.lang3.StringUtils; 15 | import org.springframework.beans.BeanUtils; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.web.bind.annotation.*; 18 | 19 | import javax.servlet.http.HttpServletRequest; 20 | import javax.validation.Valid; 21 | import java.util.UUID; 22 | 23 | /** 24 | * @author vercen 25 | * @version 1.0 26 | * @date 2023/5/25 10:47 27 | */ 28 | @Slf4j 29 | @RestController 30 | @RequestMapping("passport") 31 | @Api(tags = "通行证,验证码登录注册") 32 | public class PassportController extends BaseInfoProperties { 33 | @Autowired 34 | SMSUtils smsUtils; 35 | @Autowired 36 | UserService userService; 37 | @PostMapping("getSMSCode") 38 | public Object getSMSCode(@RequestParam String mobile, HttpServletRequest request) throws Exception { 39 | if (StringUtils.isBlank(mobile)){ 40 | return GraceJSONResult.ok(); 41 | } 42 | 43 | //TODO 获得用户ip 限制时间60s只能1次 44 | String userIp=IPUtil.getRequestIp(request); 45 | 46 | redis.setnx60s(MOBILE_SMSCODE+":"+userIp, userIp); 47 | String code=(int)((Math.random()*9+1)*100000)+""; 48 | 49 | smsUtils.sendSMS(mobile,code); 50 | 51 | log.info(code); 52 | redis.set(MOBILE_SMSCODE+":"+mobile, code,30*60); 53 | //TODO 验证码放入redis 54 | return GraceJSONResult.ok(); 55 | } 56 | 57 | @PostMapping("login") 58 | public Object login(@Valid @RequestBody RegistLoginBO registLoginBO){ 59 | 60 | String rediscode = redis.get(MOBILE_SMSCODE + ":" + registLoginBO.getMobile()); 61 | 62 | if (StringUtils.isBlank(rediscode)|| !rediscode.equalsIgnoreCase(registLoginBO.getSmsCode())){ 63 | System.out.println("rediscode"+rediscode); 64 | System.out.println("registLoginBO.getMobile()"+registLoginBO.getSmsCode()); 65 | return GraceJSONResult.errorCustom(ResponseStatusEnum.SMS_CODE_ERROR); 66 | } 67 | 68 | Users user = userService.queryMobileIsExist(registLoginBO.getMobile()); 69 | if (user==null){ 70 | user = userService.createUser(registLoginBO.getMobile()); 71 | } 72 | String uToken = UUID.randomUUID().toString(); 73 | redis.set(REDIS_USER_TOKEN+":"+user.getId(),uToken); 74 | 75 | //清除验证码 76 | redis.del(MOBILE_SMSCODE+":"+user.getMobile()); 77 | 78 | //返回给前端 79 | UsersVO usersVO = new UsersVO(); 80 | BeanUtils.copyProperties(user, usersVO); 81 | usersVO.setUserToken(uToken); 82 | 83 | return GraceJSONResult.ok(usersVO); 84 | 85 | } 86 | 87 | @PostMapping("logout") 88 | public Object logout(@RequestParam String userId){ 89 | 90 | redis.del(REDIS_USER_TOKEN+":"+userId); 91 | 92 | return GraceJSONResult.ok(); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/controller/RabbitMQConsumer.java: -------------------------------------------------------------------------------- 1 | package com.imooc.controller; 2 | 3 | import com.imooc.base.RabbitMQConfig; 4 | import com.imooc.enums.MessageEnum; 5 | import com.imooc.exceptions.GraceException; 6 | import com.imooc.grace.result.ResponseStatusEnum; 7 | import com.imooc.mo.MessageMO; 8 | import com.imooc.service.MsgService; 9 | import com.imooc.utils.JsonUtils; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.amqp.core.Message; 12 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Slf4j 17 | @Component 18 | public class RabbitMQConsumer { 19 | 20 | @Autowired 21 | private MsgService msgService; 22 | 23 | @RabbitListener(queues = {RabbitMQConfig.QUEUE_SYS_MSG}) 24 | public void watchQueue(String payload, Message message) { 25 | log.info(payload); 26 | 27 | MessageMO messageMO = JsonUtils.jsonToPojo(payload, MessageMO.class); 28 | 29 | String routingKey = message.getMessageProperties().getReceivedRoutingKey(); 30 | log.info(routingKey); 31 | 32 | // TODO: 下面这段代码可以优化,一个地方是参数优化,另外是枚举的判断优化 33 | 34 | if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.FOLLOW_YOU.enValue)) { 35 | msgService.createMsg(messageMO.getFromUserId(), 36 | messageMO.getToUserId(), 37 | MessageEnum.FOLLOW_YOU.type, 38 | null); 39 | } else if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.LIKE_VLOG.enValue)) { 40 | msgService.createMsg(messageMO.getFromUserId(), 41 | messageMO.getToUserId(), 42 | MessageEnum.FOLLOW_YOU.type, 43 | messageMO.getMsgContent()); 44 | } else if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.COMMENT_VLOG.enValue)) { 45 | msgService.createMsg(messageMO.getFromUserId(), 46 | messageMO.getToUserId(), 47 | MessageEnum.COMMENT_VLOG.type, 48 | messageMO.getMsgContent()); 49 | } else if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.REPLY_YOU.enValue)) { 50 | msgService.createMsg(messageMO.getFromUserId(), 51 | messageMO.getToUserId(), 52 | MessageEnum.REPLY_YOU.type, 53 | messageMO.getMsgContent()); 54 | } else if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.LIKE_COMMENT.enValue)) { 55 | msgService.createMsg(messageMO.getFromUserId(), 56 | messageMO.getToUserId(), 57 | MessageEnum.LIKE_COMMENT.type, 58 | messageMO.getMsgContent()); 59 | } else { 60 | GraceException.display(ResponseStatusEnum.SYSTEM_OPERATION_ERROR); 61 | } 62 | 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/controller/UserInfoController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.controller; 2 | 3 | import com.imooc.base.BaseInfoProperties; 4 | import com.imooc.bo.UpdatedUserBO; 5 | import com.imooc.config.MinIOConfig; 6 | import com.imooc.enums.FileTypeEnum; 7 | import com.imooc.enums.UserInfoModifyType; 8 | import com.imooc.grace.result.GraceJSONResult; 9 | import com.imooc.grace.result.ResponseStatusEnum; 10 | import com.imooc.pojo.Users; 11 | import com.imooc.service.UserService; 12 | import com.imooc.utils.MinIOUtils; 13 | import com.imooc.utils.SMSUtils; 14 | import com.imooc.vo.UsersVO; 15 | import io.swagger.annotations.Api; 16 | import io.swagger.annotations.ApiOperation; 17 | import lombok.extern.slf4j.Slf4j; 18 | import org.apache.commons.lang3.StringUtils; 19 | import org.springframework.beans.BeanUtils; 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.stereotype.Controller; 22 | import org.springframework.web.bind.annotation.*; 23 | import org.springframework.web.multipart.MultipartFile; 24 | 25 | /** 26 | * @author vercen 27 | * @version 1.0 28 | * @date 2023/5/20 14:32 29 | */ 30 | @RestController 31 | @Slf4j 32 | @Api(tags = "UserInfoController用户信息接口模块") 33 | @RequestMapping("userInfo") 34 | public class UserInfoController extends BaseInfoProperties { 35 | 36 | @Autowired 37 | UserService userService; 38 | 39 | // @ResponseBody 40 | @ApiOperation(value = "根据userId返回个人信息") 41 | @GetMapping("query") 42 | public Object query(@RequestParam String userId){ 43 | Users user = userService.getUser(userId); 44 | 45 | UsersVO usersVO = new UsersVO(); 46 | BeanUtils.copyProperties(user, usersVO); 47 | 48 | 49 | // 我的关注博主总数量 50 | String myFollowsCountsStr = redis.get(REDIS_MY_FOLLOWS_COUNTS + ":" + userId); 51 | // 我的粉丝总数 52 | String myFansCountsStr = redis.get(REDIS_MY_FANS_COUNTS + ":" + userId); 53 | // 用户获赞总数,视频博主(点赞/喜欢)总和 54 | // String likedVlogCountsStr = redis.get(REDIS_VLOG_BE_LIKED_COUNTS + ":" + userId); 55 | String likedVlogerCountsStr = redis.get(REDIS_VLOGER_BE_LIKED_COUNTS + ":" + userId); 56 | 57 | Integer myFollowsCounts = 0; 58 | Integer myFansCounts = 0; 59 | Integer likedVlogCounts = 0; 60 | Integer likedVlogerCounts = 0; 61 | Integer totalLikeMeCounts = 0; 62 | 63 | 64 | if (StringUtils.isNotBlank(myFollowsCountsStr)) { 65 | myFollowsCounts = Integer.valueOf(myFollowsCountsStr); 66 | } 67 | if (StringUtils.isNotBlank(myFansCountsStr)) { 68 | myFansCounts = Integer.valueOf(myFansCountsStr); 69 | } 70 | // if (StringUtils.isNotBlank(likedVlogCountsStr)) { 71 | // likedVlogCounts = Integer.valueOf(likedVlogCountsStr); 72 | // } 73 | if (StringUtils.isNotBlank(likedVlogerCountsStr)) { 74 | likedVlogerCounts = Integer.valueOf(likedVlogerCountsStr); 75 | } 76 | totalLikeMeCounts = likedVlogCounts + likedVlogerCounts; 77 | 78 | usersVO.setMyFollowsCounts(myFollowsCounts); 79 | usersVO.setMyFansCounts(myFansCounts); 80 | usersVO.setTotalLikeMeCounts(totalLikeMeCounts); 81 | 82 | //usersVO.setMyFansCounts((Integer) myFansCounts); 83 | 84 | return GraceJSONResult.ok(usersVO); 85 | } 86 | 87 | @PostMapping("modifyUserInfo") 88 | public GraceJSONResult modifyUserInfo(@RequestBody UpdatedUserBO updatedUserBO, @RequestParam Integer type) throws Exception { 89 | 90 | UserInfoModifyType.checkUserInfoTypeIsRight(type); 91 | Users newUserInfo = userService.updateUserInfo(updatedUserBO, type); 92 | return GraceJSONResult.ok(newUserInfo); 93 | } 94 | 95 | @Autowired 96 | private MinIOConfig minIOConfig; 97 | 98 | @PostMapping("modifyImage") 99 | public GraceJSONResult modifyImage(@RequestParam String userId, 100 | @RequestParam Integer type, 101 | MultipartFile file) throws Exception { 102 | 103 | if (type != FileTypeEnum.BGIMG.type && type != FileTypeEnum.FACE.type) { 104 | return GraceJSONResult.errorCustom(ResponseStatusEnum.FILE_UPLOAD_FAILD); 105 | } 106 | 107 | String fileName = file.getOriginalFilename(); 108 | 109 | MinIOUtils.uploadFile(minIOConfig.getBucketName(), 110 | fileName, 111 | file.getInputStream()); 112 | 113 | String imgUrl = minIOConfig.getFileHost() 114 | + "/" 115 | + minIOConfig.getBucketName() 116 | + "/" 117 | + fileName; 118 | 119 | 120 | // 修改图片地址到数据库 121 | UpdatedUserBO updatedUserBO = new UpdatedUserBO(); 122 | updatedUserBO.setId(userId); 123 | 124 | if (type == FileTypeEnum.BGIMG.type) { 125 | updatedUserBO.setBgImg(imgUrl); 126 | } else { 127 | updatedUserBO.setFace(imgUrl); 128 | } 129 | Users users = userService.updateUserInfo(updatedUserBO); 130 | 131 | return GraceJSONResult.ok(users); 132 | } 133 | 134 | 135 | 136 | } 137 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/intercepter/PassportInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.imooc.intercepter; 2 | 3 | import com.imooc.base.BaseInfoProperties; 4 | import com.imooc.exceptions.GraceException; 5 | import com.imooc.grace.result.ResponseStatusEnum; 6 | import com.imooc.utils.IPUtil; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.web.servlet.HandlerInterceptor; 9 | import org.springframework.web.servlet.ModelAndView; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | 14 | @Slf4j 15 | public class PassportInterceptor extends BaseInfoProperties implements HandlerInterceptor { 16 | 17 | @Override 18 | public boolean preHandle(HttpServletRequest request, 19 | HttpServletResponse response, Object handler) throws Exception { 20 | 21 | // 获得用户的ip 22 | String userIp = IPUtil.getRequestIp(request); 23 | 24 | // 得到是否存在的判断 25 | boolean keyIsExist = redis.keyIsExist(MOBILE_SMSCODE + ":" + userIp); 26 | 27 | if (keyIsExist) { 28 | GraceException.display(ResponseStatusEnum.SMS_NEED_WAIT_ERROR); 29 | log.info("短信发送频率太大!"); 30 | return false; 31 | } 32 | 33 | /** 34 | * true: 请求放行 35 | * false: 请求拦截 36 | */ 37 | return true; 38 | } 39 | 40 | @Override 41 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 42 | } 43 | 44 | @Override 45 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /book-api/src/main/java/com/imooc/intercepter/UserTokenInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.imooc.intercepter; 2 | 3 | import com.imooc.base.BaseInfoProperties; 4 | import com.imooc.exceptions.GraceException; 5 | import com.imooc.grace.result.ResponseStatusEnum; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.springframework.web.servlet.HandlerInterceptor; 9 | import org.springframework.web.servlet.ModelAndView; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | 14 | @Slf4j 15 | public class UserTokenInterceptor extends BaseInfoProperties implements HandlerInterceptor { 16 | 17 | @Override 18 | public boolean preHandle(HttpServletRequest request, 19 | HttpServletResponse response, Object handler) throws Exception { 20 | 21 | 22 | // 从header中获得用户id和token 23 | String userId = request.getHeader("headerUserId"); 24 | String userToken = request.getHeader("headerUserToken"); 25 | 26 | // 判断header中用户id和token不能为空 27 | if (StringUtils.isNotBlank(userId) && StringUtils.isNotBlank(userToken)) { 28 | String redisToken = redis.get(REDIS_USER_TOKEN + ":" + userId); 29 | if (StringUtils.isBlank(redisToken)) { 30 | GraceException.display(ResponseStatusEnum.UN_LOGIN); 31 | return false; 32 | } else { 33 | // 比较token是否一致,如果不一致,表示用户在别的手机端登录 34 | if (!redisToken.equalsIgnoreCase(userToken)) { 35 | GraceException.display(ResponseStatusEnum.TICKET_INVALID); 36 | return false; 37 | } 38 | } 39 | } else { 40 | GraceException.display(ResponseStatusEnum.UN_LOGIN); 41 | return false; 42 | } 43 | 44 | /** 45 | * true: 请求放行 46 | * false: 请求拦截 47 | */ 48 | return true; 49 | } 50 | 51 | @Override 52 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 53 | } 54 | 55 | @Override 56 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /book-api/src/main/resources/application-dev.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: ${port:8099} 3 | 4 | spring: 5 | datasource: # 数据源的相关配置 6 | type: com.zaxxer.hikari.HikariDataSource # 数据源的类型,可以更改为其他的数据源配置,比如druid 7 | driver-class-name: com.mysql.jdbc.Driver # mysql/MariaDB 的数据库驱动类名称 8 | url: jdbc:mysql://192.168.1.7:3306/imooc-red-book-dev?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true 9 | username: root 10 | password: root 11 | hikari: 12 | connection-timeout: 30000 # 等待连接池分配连接的最大时间(毫秒),超过这个时长还没有可用的连接,则会抛出SQLException 13 | minimum-idle: 5 # 最小连接数 14 | maximum-pool-size: 20 # 最大连接数 15 | auto-commit: true # 自动提交 16 | idle-timeout: 600000 # 连接超时的最大时长(毫秒),超时则会被释放(retired) 17 | pool-name: DataSourceHikariCP # 连接池的名字 18 | max-lifetime: 18000000 # 连接池的最大生命时长(毫秒),超时则会被释放(retired) 19 | connection-test-query: SELECT 1 20 | redis: 21 | host: 192.168.1.61 22 | port: 6379 23 | database: 0 24 | password: itzixi 25 | data: 26 | mongodb: 27 | uri: mongodb://root:root@192.168.1.202:27017 28 | database: imooc-red-book 29 | rabbitmq: 30 | host: 192.168.1.204 31 | port: 5672 32 | username: admin 33 | password: admin 34 | virtual-host: imooc-red-book 35 | # application: 36 | # name: imooc-red-book-nacos 37 | cloud: 38 | nacos: 39 | discovery: 40 | server-addr: 192.168.1.159:8848 # nacos 所在的地址 41 | 42 | #counts: 100 43 | 44 | # 打开监控 45 | management: 46 | endpoint: 47 | web: 48 | exposure: 49 | include: '*' 50 | 51 | # MinIO 配置 52 | minio: 53 | endpoint: http://192.168.1.61:9000 # MinIO服务地址 54 | fileHost: http://192.168.1.61:9000 # 文件地址host 55 | bucketName: imooc # 存储桶bucket名称 56 | accessKey: imooc # 用户名 57 | secretKey: imooc123456 # 密码 58 | imgSize: 1024 # 图片大小限制,单位:m 59 | fileSize: 1024 # 文件大小限制,单位:m 60 | -------------------------------------------------------------------------------- /book-api/src/main/resources/application-prod.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | 4 | spring: 5 | datasource: # 数据源的相关配置 6 | type: com.zaxxer.hikari.HikariDataSource # 数据源的类型,可以更改为其他的数据源配置,比如druid 7 | driver-class-name: com.mysql.jdbc.Driver # mysql/MariaDB 的数据库驱动类名称 8 | url: jdbc:mysql://10.206.0.11:3306/imooc-red-book?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true 9 | username: root 10 | password: imooc 11 | hikari: 12 | connection-timeout: 30000 # 等待连接池分配连接的最大时间(毫秒),超过这个时长还没有可用的连接,则会抛出SQLException 13 | minimum-idle: 5 # 最小连接数 14 | maximum-pool-size: 20 # 最大连接数 15 | auto-commit: true # 自动提交 16 | idle-timeout: 600000 # 连接超时的最大时长(毫秒),超时则会被释放(retired) 17 | pool-name: DataSourceHikariCP # 连接池的名字 18 | max-lifetime: 18000000 # 连接池的最大生命时长(毫秒),超时则会被释放(retired) 19 | connection-test-query: SELECT 1 20 | redis: 21 | host: 10.206.0.11 22 | port: 6379 23 | database: 0 24 | password: imooc 25 | data: 26 | mongodb: 27 | uri: mongodb://root:root@10.206.0.11:27017 28 | database: imooc 29 | rabbitmq: 30 | host: 10.206.0.11 31 | port: 5672 32 | username: imooc 33 | password: imooc 34 | virtual-host: imooc 35 | # application: 36 | # name: imooc-red-book-nacos 37 | cloud: 38 | nacos: 39 | discovery: 40 | server-addr: 10.206.0.11:8848 # nacos 所在的地址 41 | 42 | # 打开监控 43 | management: 44 | endpoint: 45 | web: 46 | exposure: 47 | include: '*' 48 | 49 | # MinIO 配置 50 | minio: 51 | endpoint: http://175.27.252.166:9000 # MinIO服务地址 52 | fileHost: http://175.27.252.166:9000 # 文件地址host 53 | bucketName: imooc # 存储桶bucket名称 54 | accessKey: root # 用户名 55 | secretKey: 12345678 # 密码 56 | imgSize: 1024 # 图片大小限制,单位:m 57 | fileSize: 1024 # 文件大小限制,单位:m -------------------------------------------------------------------------------- /book-api/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | # port: 8099 3 | tomcat: 4 | uri-encoding: UTF-8 5 | max-swallow-size: -1 # tomcat默认大小2M,超过2M的文件不会被捕获,需要调整此处大小为100MB或者-1即可 6 | 7 | spring: 8 | application: 9 | name: imooc-red-book-nacos 10 | profiles: 11 | active: prod 12 | banner: 13 | location: classpath:banner/banner.txt 14 | servlet: 15 | multipart: 16 | max-file-size: 2MB # 文件上传大小限制,设置最大值,不能超过该值,否则报错 17 | # max-file-size: 500KB # 文件上传大小限制,设置最大值,不能超过该值,否则报错 18 | max-request-size: 2MB # 文件最大请求限制,用于批量上传 19 | # max-request-size: 500KB 20 | 21 | # 整合mybatis 22 | mybatis: 23 | type-aliases-package: com.imooc.pojo # 所有pojo类所在的包路径 24 | mapper-locations: classpath:mapper/*.xml # mapper映射文件 25 | 26 | # 通用mapper工具的配置 27 | mapper: 28 | mappers: com.imooc.my.mapper.MyMapper # 配置MyMapper,包含了一些封装好的CRUD方法 29 | not-empty: false # 在进行数据库操作的时候,username != null 是否会追加 username != '' 30 | identity: MYSQL 31 | 32 | # 分页插件助手的配置 33 | pagehelper: 34 | helper-dialect: MYSQL 35 | support-methods-arguments: true 36 | 37 | # 日志级别 38 | logging: 39 | level: 40 | root: info 41 | -------------------------------------------------------------------------------- /book-api/src/main/resources/banner/banner.txt: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////// 2 | // _ooOoo_ // 3 | // o8888888o // 4 | // 88" . "88 // 5 | // (| ^_^ |) // 6 | // O\ = /O // 7 | // ____/`---'\____ // 8 | // .' \\| |// `. // 9 | // / \\||| : |||// \ // 10 | // / _||||| -:- |||||- \ // 11 | // | | \\\ - /// | | // 12 | // | \_| ''\---/'' | | // 13 | // \ .-\__ `-` ___/-. / // 14 | // ___`. .' /--.--\ `. . ___ // 15 | // ."" '< `.___\_<|>_/___.' >'"". // 16 | // | | : `- \`.;`\ _ /`;.`/ - ` : | | // 17 | // \ \ `-. \_ __\ /__ _/ .-` / / // 18 | // ========`-.____`-.___\_____/___.-`____.-'======== // 19 | // `=---=' // 20 | // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // 21 | // 佛祖保佑 永无BUG 永不修改 // 22 | //////////////////////////////////////////////////////////////////// -------------------------------------------------------------------------------- /book-api/src/main/resources/banner/cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vercen/vlog/403328c43b2f00cbe65b152671015aeb51c4ac7f/book-api/src/main/resources/banner/cat.png -------------------------------------------------------------------------------- /book-api/src/main/resources/banner/qiaoba.txt: -------------------------------------------------------------------------------- 1 | tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt 2 | tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt 3 | tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt 4 | ttttttttttttttttttttttttttttttttjtttjttjjtjW#Li;;ijE#Ettttjttjjjtttttttttttttttttttttttttttttttttttt 5 | ttttttttttttttttttttttttttttjtttLGtWtttt#i;itttttttjti;tWtttjWtDEjtttttttttttttttttttttttttttttttttt 6 | tttttttttttttttttttttttttttjjjttfjLjWtEjjtjtjttttttjjtjttLWt;jEjjttttttttttttttttttttttttttttttttttt 7 | ttttttttttttttttttttttttttDf;tjt;jWjjfLtttttttttttttttttttLDjjjjEtjj#ELttttttttttttttttttttttttttttt 8 | tttttttttttttttttttttttt#DjGjfjtjjtjjfLttttttttttttttttttjL#jjjjtttjtfLGfjtttttttttttttttttttttttttt 9 | tttttttttttttttttttttttttjfLjGttWjjjjLLtttttttttttttttttttLEjjjjjtttjjjjDjtttttttttttttttttttttttttt 10 | tttttttttttttttttttttttttjjjjDttLjjjjLLttttttttttttttttttjLLjLjjjttijjjjLjtttttttttttttttttttttttttt 11 | tttttttttttttttttttttttttjjjjjtttjjjfLLtttttttWEttf jtttttLDjLjjjjttEjfjLttttttttttttttttttttttttttt 12 | ttttttttttttttttttttttttijjjjjtjDjjjjLLjttttjG GL :jttttLWjjjjttKjWjKjKttttttttttttttttttttttttttt 13 | ttttttttttttttttttttttttijjjWjGjfjLjjLLjttttt,. ftttjLGjjtttj;jjj#jKjtttttttttttttttttttttttttt 14 | ttttttttttttttttttttttttEj#ffjjjfjjjWfLfjtttttf KtttttfLL;jjffjjLjjjjjttttttttttttttttttttttttttt 15 | tttttttttttttttttttttttttjjtjjjjjfLj#fLftttttjf tttttLLL#fjfjjjfjKjfttjttttttttttttttttttttttttt 16 | tttttttttttttttttttttttttDjjjjjjLjGj#LLLttttjD . . .jtttLLLWGGffjjjGjtjtttttttttttttttttttttttttttt 17 | tttttttttttttttttttttttttj;jjjjGLLDt#LLLtjjtjK Ej jtttLLLWjKLLLjjjjWttttttttttttttttttttttttttttt 18 | tttttttttttttttttttttttttttjGLLLLLLWKGLLttjtEWL;;;fKKjtttfWEWDLfLLLGWttttttttttttttttttttttttttttttt 19 | ttttttttttttttttttttttttttttttttfLLLfLGLD,,;ttjtttttti;;#LGLLLL#jttttttttttttttttttttttttttttttttttt 20 | tttttttttttttttttttttttttttttttttD::.#G;;jtjjjtttttjjtjtti;W:,:Wtttttttttttttttttttttttttttttttttttt 21 | ttttttttttttttttttttttttttttttttt;EjW,jtjjjjttjjttjtjtjjjjtj,Lj;jttttttttttttttttttttttttttttttttttt 22 | tttttttttttttttttttttttttttttttttE;;tjjtjjjKLLLLLLLLLGKjtjtjLLiWjttttttttttttttttttttttttttttttttttt 23 | tttttttttttttttttttttttttttttttttf,tjjttWLLLfLLLLLLLLfLfLKjtLLLfjttttttttttttttttttttttttttttttttttt 24 | ttttttttttttttttttttttttttttttttj,jjttEfLLLLLLLLLLLLLLLLLLLELLLLLttttttttttttttttttttttttttttttttttt 25 | tttttttttttttttttttttttttttttttjittjtfLLLLLLLLfDEKDLfLfLfLfLLfLLLWtttttttttttttttttttttttttttttttttt 26 | tttttttttttttttttttttttttttttttttjjffLLLLEGfjjjfjjjjjjGjKLLLfLfLLftjtttttttttttttttttttttttttttttttt 27 | ttttttttttttttttttttttttttttttttjjjLLLLKfjj;j;;;;;;;;,;jfjWLLLfLfLtttttttttttttttttttttttttttttttttt 28 | ttttttttttttttttttttttttttttttttttKLLLKf;ifj;i;;;;;;;j.E;;fLLLLGLLtttttttttttttttttttttttttttttttttt 29 | tttttttttttttttttttttttttttttttjtjLLLEG,;DWKWi;;;;;;;WWKE;;LfLLLLGtttttttttttttttttttttttttttttttttt 30 | ttttttttttttttttttttttttttttttttWELLLLL;; WKKD;;;;;;jKKK.;;LLLLLWftttttttttttttttttttttttttttttttttt 31 | tttttttttttttttttttttttttttttttttffLLLL:;EWKW,,;Di,;;KWKf;;fLLLLLjtttttttttttttttttttttttttttttttttt 32 | tttttttttttttttttttttttttttttttttWLLLLLE;,E.;;;;;,;;;;tDi;#LLLLfDttttttttttttttttttttttttttttttttttt 33 | ttttttttttttttttttttttttttttttttttKLLLLL;;;;;;;;tK,L;;;;;;LLLLfLtttttttttttttttttttttttttttttttttttt 34 | tttttttttttttttttttttttttttttttttttjLLLLW,;;;;;EEED;;;;;;WLLLDtttttttttttttttttttttttttttttttttttttt 35 | ttttttttttttttttttttttttttttttttttttjtKEL,;;;;;EjjW;;;;;KtEGjjjttttttttttttttttttttttttttttttttttttt 36 | ttttttttttttttttttttttttttttttttttttjtttttW,,;;jttj,i;tWKffKfjtttttttttttttttttttttttttttttttttttttt 37 | tttttttttttttttttttttttttttttttttttttttttttttDLjttfGWtjti,;Kjttttttttttttttttttttttttttttttttttttttt 38 | tttttttttttttttttttttttttttttttttttttttttttttDjittfj;,;;D;;;;ttttttttttttttttttttttttttttttttttttttt 39 | ttttttttttttttttttttttttttttttttttttttttttttE;;EEjWi;DGKj,iEjtjttttttttttttttttttttttttttttttttttttt 40 | tttttttttttttttttttttttttttttttttttttttttttt;,;;WWt;;;Dtttfttttttttttttttttttttttttttttttttttttttttt 41 | ttttttttttttttttttttttttttttttttttttttttttt;t;;;;;;;;;;Gtttttttttttttttttttttttttttttttttttttttttttt 42 | ttttttttttttttttttttttttttttttttttttttttjj,K;;;;;;;;;;;;jttttttttttttttttttttttttttttttttttttttttttt 43 | tttttttttttttttttttttttttttttttttttttttjf;;j;;;;;;;;;;;;tttttttttttttttttttttttttttttttttttttttttttt 44 | tttttttttttttttttttttttttttttttttttttttftGKE;;,;,,;;;;;ijttttttttttttttttttttttttttttttttttttttttttt 45 | tttttttttttttttttttttttttttttttttttttttEfijDGGGGGGGGGGGKjttttttttttttttttttttttttttttttttttttttttttt 46 | ttttttttttttttttttttttttttttttttttttttttfjtGGGGGGGGGGEDWtttttttttttttttttttttttttttttttttttttttttttt 47 | tttttttttttttttttttttttttttttttttttttttttttfEEDEEEEEEEKttttttttttttttttttttttttttttttttttttttttttttt 48 | tttttttttttttttttttttttttttttttttttttttttttttLDEWWEEEttttttttttttttttttttttttttttttttttttttttttttttt 49 | ttttttttttttttttttttttttttttttttttttttttttjtttKWjtKWjttttttttttttttttttttttttttttttttttttttttttttttt 50 | tttttttttttttttttttttttttttttttttttttttttttttttEjtjjijtttttttttttttttttttttttttttttttttttttttttttttt 51 | tttttttttttttttttttttttttttttttttttttttttttttK,Gttf,fDtttttttttttttttttttttttttttttttttttttttttttttt 52 | ttttttttttttttttttttttttttttttttttttttttttttWjD;tt;,fWtttttttttttttttttttttttttttttttttttttttttttttt 53 | ttttttttttttttttttttttttttttttttttttttttttttttjttttttttttttttttttttttttttttttttttttttttttttttttttttt 54 | tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt 55 | tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt 56 | tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt 57 | tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt -------------------------------------------------------------------------------- /book-api/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: imooc-red-book-nacos 4 | cloud: 5 | nacos: 6 | config: 7 | server-addr: 10.206.0.11:8848 # nacos 所在的地址 8 | file-extension: yaml -------------------------------------------------------------------------------- /book-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.imooc 8 | imooc-red-book-dev 9 | 1.0-SNAPSHOT 10 | 11 | 12 | book-common 13 | 14 | 15 | 8 16 | 8 17 | UTF-8 18 | 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-configuration-processor 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-aop 37 | 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-data-redis 43 | 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-amqp 49 | 50 | 51 | 52 | 53 | org.projectlombok 54 | lombok 55 | 56 | 57 | 58 | 59 | com.fasterxml.jackson.core 60 | jackson-core 61 | 62 | 63 | com.fasterxml.jackson.core 64 | jackson-annotations 65 | 66 | 67 | com.fasterxml.jackson.core 68 | jackson-databind 69 | 70 | 71 | 72 | commons-codec 73 | commons-codec 74 | 75 | 76 | org.apache.commons 77 | commons-lang3 78 | 79 | 80 | commons-fileupload 81 | commons-fileupload 82 | 83 | 84 | 85 | com.google.guava 86 | guava 87 | 88 | 89 | 90 | joda-time 91 | joda-time 92 | 93 | 94 | 95 | 96 | com.tencentcloudapi 97 | tencentcloud-sdk-java 98 | 3.1.270 99 | 100 | 101 | 102 | io.minio 103 | minio 104 | 8.2.1 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/enums/FileTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.imooc.enums; 2 | 3 | /** 4 | * @Desc: 文件类型 枚举 5 | */ 6 | public enum FileTypeEnum { 7 | BGIMG(1, "用户背景图"), 8 | FACE(2, "用户头像"); 9 | 10 | public final Integer type; 11 | public final String value; 12 | 13 | FileTypeEnum(Integer type, String value) { 14 | this.type = type; 15 | this.value = value; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/enums/MessageEnum.java: -------------------------------------------------------------------------------- 1 | package com.imooc.enums; 2 | 3 | /** 4 | * @Desc: 消息类型 5 | */ 6 | public enum MessageEnum { 7 | FOLLOW_YOU(1, "关注", "follow"), 8 | LIKE_VLOG(2, "点赞视频", "likeVideo"), 9 | COMMENT_VLOG(3, "评论视频", "comment"), 10 | REPLY_YOU(4, "回复评论", "replay"), 11 | LIKE_COMMENT(5, "点赞评论", "likeComment"); 12 | 13 | public final Integer type; 14 | public final String value; 15 | public final String enValue; 16 | 17 | MessageEnum(Integer type, String value, String enValue) { 18 | this.type = type; 19 | this.value = value; 20 | this.enValue = enValue; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/enums/Sex.java: -------------------------------------------------------------------------------- 1 | package com.imooc.enums; 2 | 3 | /** 4 | * @Desc: 性别 枚举 5 | */ 6 | public enum Sex { 7 | woman(0, "女"), 8 | man(1, "男"), 9 | secret(2, "保密"); 10 | 11 | public final Integer type; 12 | public final String value; 13 | 14 | Sex(Integer type, String value) { 15 | this.type = type; 16 | this.value = value; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/enums/UserInfoModifyType.java: -------------------------------------------------------------------------------- 1 | package com.imooc.enums; 2 | 3 | import com.imooc.exceptions.GraceException; 4 | import com.imooc.grace.result.ResponseStatusEnum; 5 | 6 | /** 7 | * @Desc: 修改用户信息类型 枚举 8 | */ 9 | public enum UserInfoModifyType { 10 | NICKNAME(1, "昵称"), 11 | IMOOCNUM(2, "慕课号"), 12 | SEX(3, "性别"), 13 | BIRTHDAY(4, "生日"), 14 | LOCATION(5, "所在地"), 15 | DESC(6, "简介"); 16 | 17 | public final Integer type; 18 | public final String value; 19 | 20 | UserInfoModifyType(Integer type, String value) { 21 | this.type = type; 22 | this.value = value; 23 | } 24 | 25 | public static void checkUserInfoTypeIsRight(Integer type) { 26 | if (type != UserInfoModifyType.NICKNAME.type && 27 | type != UserInfoModifyType.IMOOCNUM.type && 28 | type != UserInfoModifyType.SEX.type && 29 | type != UserInfoModifyType.BIRTHDAY.type && 30 | type != UserInfoModifyType.LOCATION.type && 31 | type != UserInfoModifyType.DESC.type) { 32 | GraceException.display(ResponseStatusEnum.USER_INFO_UPDATED_ERROR); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/enums/YesOrNo.java: -------------------------------------------------------------------------------- 1 | package com.imooc.enums; 2 | 3 | /** 4 | * @Desc: 是否 枚举 5 | */ 6 | public enum YesOrNo { 7 | NO(0, "否"), 8 | YES(1, "是"); 9 | 10 | public final Integer type; 11 | public final String value; 12 | 13 | YesOrNo(Integer type, String value) { 14 | this.type = type; 15 | this.value = value; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/exceptions/GraceException.java: -------------------------------------------------------------------------------- 1 | package com.imooc.exceptions; 2 | 3 | import com.imooc.grace.result.ResponseStatusEnum; 4 | 5 | /** 6 | * 优雅的处理异常,统一封装 7 | */ 8 | public class GraceException { 9 | 10 | public static void display(ResponseStatusEnum responseStatusEnum) { 11 | throw new MyCustomException(responseStatusEnum); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/exceptions/GraceExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.imooc.exceptions; 2 | 3 | import com.imooc.grace.result.GraceJSONResult; 4 | import com.imooc.grace.result.ResponseStatusEnum; 5 | import org.springframework.validation.BindingResult; 6 | import org.springframework.validation.FieldError; 7 | import org.springframework.web.bind.MethodArgumentNotValidException; 8 | import org.springframework.web.bind.annotation.ControllerAdvice; 9 | import org.springframework.web.bind.annotation.ExceptionHandler; 10 | import org.springframework.web.bind.annotation.ResponseBody; 11 | import org.springframework.web.multipart.MaxUploadSizeExceededException; 12 | 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | /** 18 | * 统一异常拦截处理 19 | * 可以针对异常的类型进行捕获,然后返回json信息到前端 20 | */ 21 | @ControllerAdvice 22 | public class GraceExceptionHandler { 23 | 24 | @ExceptionHandler(MyCustomException.class) 25 | @ResponseBody 26 | public GraceJSONResult returnMyException(MyCustomException e) { 27 | //e.printStackTrace(); 28 | return GraceJSONResult.exception(e.getResponseStatusEnum()); 29 | } 30 | 31 | @ExceptionHandler(MethodArgumentNotValidException.class) 32 | @ResponseBody 33 | public GraceJSONResult returnMethodArgumentNotValid(MethodArgumentNotValidException e) { 34 | BindingResult result = e.getBindingResult(); 35 | Map map = getErrors(result); 36 | return GraceJSONResult.errorMap(map); 37 | } 38 | 39 | @ExceptionHandler(MaxUploadSizeExceededException.class) 40 | @ResponseBody 41 | public GraceJSONResult returnMaxUploadSize(MaxUploadSizeExceededException e) { 42 | // e.printStackTrace(); 43 | return GraceJSONResult.errorCustom(ResponseStatusEnum.FILE_MAX_SIZE_2MB_ERROR); 44 | } 45 | 46 | public Map getErrors(BindingResult result) { 47 | Map map = new HashMap<>(); 48 | List errorList = result.getFieldErrors(); 49 | for (FieldError ff : errorList) { 50 | // 错误所对应的属性字段名 51 | String field = ff.getField(); 52 | // 错误的信息 53 | String msg = ff.getDefaultMessage(); 54 | map.put(field, msg); 55 | } 56 | return map; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/exceptions/MyCustomException.java: -------------------------------------------------------------------------------- 1 | package com.imooc.exceptions; 2 | 3 | import com.imooc.grace.result.ResponseStatusEnum; 4 | 5 | /** 6 | * 自定义异常 7 | * 目的:统一处理异常信息 8 | * 便于解耦,拦截器、service与controller 异常错误的解耦, 9 | * 不会被service返回的类型而限制 10 | */ 11 | public class MyCustomException extends RuntimeException { 12 | 13 | private ResponseStatusEnum responseStatusEnum; 14 | 15 | public MyCustomException(ResponseStatusEnum responseStatusEnum) { 16 | super("异常状态码为:" + responseStatusEnum.status() 17 | + ";具体异常信息为:" + responseStatusEnum.msg()); 18 | this.responseStatusEnum = responseStatusEnum; 19 | } 20 | 21 | public ResponseStatusEnum getResponseStatusEnum() { 22 | return responseStatusEnum; 23 | } 24 | 25 | public void setResponseStatusEnum(ResponseStatusEnum responseStatusEnum) { 26 | this.responseStatusEnum = responseStatusEnum; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/grace/result/GraceJSONResult.java: -------------------------------------------------------------------------------- 1 | package com.imooc.grace.result; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 自定义响应数据类型枚举升级版本 7 | * 8 | * @Title: IMOOCJSONResult.java 9 | * @Package com.imooc.utils 10 | * @Description: 自定义响应数据结构 11 | * 本类可提供给 H5/ios/安卓/公众号/小程序 使用 12 | * 前端接受此类数据(json object)后,可自行根据业务去实现相关功能 13 | * 14 | * @Copyright: Copyright (c) 2020 15 | * @Company: www.imooc.com 16 | * @author 慕课网 - 风间影月 17 | * @version V2.0 18 | */ 19 | public class GraceJSONResult { 20 | 21 | // 响应业务状态码 22 | private Integer status; 23 | 24 | // 响应消息 25 | private String msg; 26 | 27 | // 是否成功 28 | private Boolean success; 29 | 30 | // 响应数据,可以是Object,也可以是List或Map等 31 | private Object data; 32 | 33 | /** 34 | * 成功返回,带有数据的,直接往OK方法丢data数据即可 35 | * @param data 36 | * @return 37 | */ 38 | public static GraceJSONResult ok(Object data) { 39 | return new GraceJSONResult(data); 40 | } 41 | /** 42 | * 成功返回,不带有数据的,直接调用ok方法,data无须传入(其实就是null) 43 | * @return 44 | */ 45 | public static GraceJSONResult ok() { 46 | return new GraceJSONResult(ResponseStatusEnum.SUCCESS); 47 | } 48 | public GraceJSONResult(Object data) { 49 | this.status = ResponseStatusEnum.SUCCESS.status(); 50 | this.msg = ResponseStatusEnum.SUCCESS.msg(); 51 | this.success = ResponseStatusEnum.SUCCESS.success(); 52 | this.data = data; 53 | } 54 | 55 | 56 | /** 57 | * 错误返回,直接调用error方法即可,当然也可以在ResponseStatusEnum中自定义错误后再返回也都可以 58 | * @return 59 | */ 60 | public static GraceJSONResult error() { 61 | return new GraceJSONResult(ResponseStatusEnum.FAILED); 62 | } 63 | 64 | /** 65 | * 错误返回,map中包含了多条错误信息,可以用于表单验证,把错误统一的全部返回出去 66 | * @param map 67 | * @return 68 | */ 69 | public static GraceJSONResult errorMap(Map map) { 70 | return new GraceJSONResult(ResponseStatusEnum.FAILED, map); 71 | } 72 | 73 | /** 74 | * 错误返回,直接返回错误的消息 75 | * @param msg 76 | * @return 77 | */ 78 | public static GraceJSONResult errorMsg(String msg) { 79 | return new GraceJSONResult(ResponseStatusEnum.FAILED, msg); 80 | } 81 | 82 | /** 83 | * 错误返回,token异常,一些通用的可以在这里统一定义 84 | * @return 85 | */ 86 | public static GraceJSONResult errorTicket() { 87 | return new GraceJSONResult(ResponseStatusEnum.TICKET_INVALID); 88 | } 89 | 90 | /** 91 | * 自定义错误范围,需要传入一个自定义的枚举,可以到[ResponseStatusEnum.java[中自定义后再传入 92 | * @param responseStatus 93 | * @return 94 | */ 95 | public static GraceJSONResult errorCustom(ResponseStatusEnum responseStatus) { 96 | return new GraceJSONResult(responseStatus); 97 | } 98 | public static GraceJSONResult exception(ResponseStatusEnum responseStatus) { 99 | return new GraceJSONResult(responseStatus); 100 | } 101 | 102 | public GraceJSONResult(ResponseStatusEnum responseStatus) { 103 | this.status = responseStatus.status(); 104 | this.msg = responseStatus.msg(); 105 | this.success = responseStatus.success(); 106 | } 107 | public GraceJSONResult(ResponseStatusEnum responseStatus, Object data) { 108 | this.status = responseStatus.status(); 109 | this.msg = responseStatus.msg(); 110 | this.success = responseStatus.success(); 111 | this.data = data; 112 | } 113 | public GraceJSONResult(ResponseStatusEnum responseStatus, String msg) { 114 | this.status = responseStatus.status(); 115 | this.msg = msg; 116 | this.success = responseStatus.success(); 117 | } 118 | 119 | public GraceJSONResult() { 120 | } 121 | 122 | public Integer getStatus() { 123 | return status; 124 | } 125 | 126 | public void setStatus(Integer status) { 127 | this.status = status; 128 | } 129 | 130 | public String getMsg() { 131 | return msg; 132 | } 133 | 134 | public void setMsg(String msg) { 135 | this.msg = msg; 136 | } 137 | 138 | public Object getData() { 139 | return data; 140 | } 141 | 142 | public void setData(Object data) { 143 | this.data = data; 144 | } 145 | 146 | public Boolean getSuccess() { 147 | return success; 148 | } 149 | 150 | public void setSuccess(Boolean success) { 151 | this.success = success; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/grace/result/IMOOCJSONResult.java: -------------------------------------------------------------------------------- 1 | package com.imooc.grace.result; 2 | 3 | /** 4 | * 5 | * @Title: IMOOCJSONResult.java 6 | * @Package com.imooc.utils 7 | * @Description: 自定义响应数据结构 8 | * 本类可提供给 H5/ios/安卓/公众号/小程序 使用 9 | * 前端接受此类数据(json object)后,可自行根据业务去实现相关功能 10 | * 11 | * 200:表示成功 12 | * 500:表示错误,错误信息在msg字段中 13 | * 501:bean验证错误,不管多少个错误都以map形式返回 14 | * 502:拦截器拦截到用户token出错 15 | * 555:异常抛出信息 16 | * 556: 用户qq校验异常 17 | * 557: 校验用户是否在CAS登录,用户门票的校验 18 | * @Copyright: Copyright (c) 2020 19 | * @Company: www.imooc.com 20 | * @author 慕课网 - 风间影月 21 | * @version V1.0 22 | */ 23 | public class IMOOCJSONResult { 24 | 25 | // 响应业务状态 26 | private Integer status; 27 | 28 | // 响应消息 29 | private String msg; 30 | 31 | // 响应中的数据 32 | private Object data; 33 | 34 | private String ok; // 不使用 35 | 36 | public static IMOOCJSONResult build(Integer status, String msg, Object data) { 37 | return new IMOOCJSONResult(status, msg, data); 38 | } 39 | 40 | public static IMOOCJSONResult build(Integer status, String msg, Object data, String ok) { 41 | return new IMOOCJSONResult(status, msg, data, ok); 42 | } 43 | 44 | public static IMOOCJSONResult ok(Object data) { 45 | return new IMOOCJSONResult(data); 46 | } 47 | 48 | public static IMOOCJSONResult ok() { 49 | return new IMOOCJSONResult(null); 50 | } 51 | 52 | public static IMOOCJSONResult errorMsg(String msg) { 53 | return new IMOOCJSONResult(500, msg, null); 54 | } 55 | 56 | public static IMOOCJSONResult errorUserTicket(String msg) { 57 | return new IMOOCJSONResult(557, msg, null); 58 | } 59 | 60 | public static IMOOCJSONResult errorMap(Object data) { 61 | return new IMOOCJSONResult(501, "error", data); 62 | } 63 | 64 | public static IMOOCJSONResult errorTokenMsg(String msg) { 65 | return new IMOOCJSONResult(502, msg, null); 66 | } 67 | 68 | public static IMOOCJSONResult errorException(String msg) { 69 | return new IMOOCJSONResult(555, msg, null); 70 | } 71 | 72 | public static IMOOCJSONResult errorUserQQ(String msg) { 73 | return new IMOOCJSONResult(556, msg, null); 74 | } 75 | 76 | public IMOOCJSONResult() { 77 | 78 | } 79 | 80 | public IMOOCJSONResult(Integer status, String msg, Object data) { 81 | this.status = status; 82 | this.msg = msg; 83 | this.data = data; 84 | } 85 | 86 | public IMOOCJSONResult(Integer status, String msg, Object data, String ok) { 87 | this.status = status; 88 | this.msg = msg; 89 | this.data = data; 90 | this.ok = ok; 91 | } 92 | 93 | public IMOOCJSONResult(Object data) { 94 | this.status = 200; 95 | this.msg = "OK"; 96 | this.data = data; 97 | } 98 | 99 | public Boolean isOK() { 100 | return this.status == 200; 101 | } 102 | 103 | public Integer getStatus() { 104 | return status; 105 | } 106 | 107 | public void setStatus(Integer status) { 108 | this.status = status; 109 | } 110 | 111 | public String getMsg() { 112 | return msg; 113 | } 114 | 115 | public void setMsg(String msg) { 116 | this.msg = msg; 117 | } 118 | 119 | public Object getData() { 120 | return data; 121 | } 122 | 123 | public void setData(Object data) { 124 | this.data = data; 125 | } 126 | 127 | public String getOk() { 128 | return ok; 129 | } 130 | 131 | public void setOk(String ok) { 132 | this.ok = ok; 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/grace/result/ResponseStatusEnum.java: -------------------------------------------------------------------------------- 1 | package com.imooc.grace.result; 2 | 3 | /** 4 | * 响应结果枚举,用于提供给GraceJSONResult返回给前端的 5 | * 本枚举类中包含了很多的不同的状态码供使用,可以自定义 6 | * 便于更优雅的对状态码进行管理,一目了然 7 | */ 8 | public enum ResponseStatusEnum { 9 | 10 | SUCCESS(200, true, "操作成功!"), 11 | FAILED(500, false, "操作失败!"), 12 | 13 | // 50x 14 | UN_LOGIN(501,false,"请登录后再继续操作!"), 15 | TICKET_INVALID(502,false,"会话失效,请重新登录!"), 16 | NO_AUTH(503,false,"您的权限不足,无法继续操作!"), 17 | MOBILE_ERROR(504,false,"短信发送失败,请稍后重试!"), 18 | SMS_NEED_WAIT_ERROR(505,false,"短信发送太快啦~请稍后再试!"), 19 | SMS_CODE_ERROR(506,false,"验证码过期或不匹配,请稍后再试!"), 20 | USER_FROZEN(507,false,"用户已被冻结,请联系管理员!"), 21 | USER_UPDATE_ERROR(508,false,"用户信息更新失败,请联系管理员!"), 22 | USER_INACTIVE_ERROR(509,false,"请前往[账号设置]修改信息激活后再进行后续操作!"), 23 | USER_INFO_UPDATED_ERROR(5091,false,"用户信息修改失败!"), 24 | USER_INFO_UPDATED_NICKNAME_EXIST_ERROR(5092,false,"昵称已经存在!"), 25 | USER_INFO_UPDATED_IMOOCNUM_EXIST_ERROR(5092,false,"慕课号已经存在!"), 26 | USER_INFO_CANT_UPDATED_IMOOCNUM_ERROR(5092,false,"慕课号无法修改!"), 27 | FILE_UPLOAD_NULL_ERROR(510,false,"文件不能为空,请选择一个文件再上传!"), 28 | FILE_UPLOAD_FAILD(511,false,"文件上传失败!"), 29 | FILE_FORMATTER_FAILD(512,false,"文件图片格式不支持!"), 30 | FILE_MAX_SIZE_500KB_ERROR(5131,false,"仅支持500kb大小以下的图片上传!"), 31 | FILE_MAX_SIZE_2MB_ERROR(5132,false,"仅支持2MB大小以下的图片上传!"), 32 | FILE_NOT_EXIST_ERROR(514,false,"你所查看的文件不存在!"), 33 | USER_STATUS_ERROR(515,false,"用户状态参数出错!"), 34 | USER_NOT_EXIST_ERROR(516,false,"用户不存在!"), 35 | 36 | // 自定义系统级别异常 54x 37 | SYSTEM_INDEX_OUT_OF_BOUNDS(541, false, "系统错误,数组越界!"), 38 | SYSTEM_ARITHMETIC_BY_ZERO(542, false, "系统错误,无法除零!"), 39 | SYSTEM_NULL_POINTER(543, false, "系统错误,空指针!"), 40 | SYSTEM_NUMBER_FORMAT(544, false, "系统错误,数字转换异常!"), 41 | SYSTEM_PARSE(545, false, "系统错误,解析异常!"), 42 | SYSTEM_IO(546, false, "系统错误,IO输入输出异常!"), 43 | SYSTEM_FILE_NOT_FOUND(547, false, "系统错误,文件未找到!"), 44 | SYSTEM_CLASS_CAST(548, false, "系统错误,类型强制转换错误!"), 45 | SYSTEM_PARSER_ERROR(549, false, "系统错误,解析出错!"), 46 | SYSTEM_DATE_PARSER_ERROR(550, false, "系统错误,日期解析出错!"), 47 | 48 | // admin 管理系统 56x 49 | ADMIN_USERNAME_NULL_ERROR(561, false, "管理员登录名不能为空!"), 50 | ADMIN_USERNAME_EXIST_ERROR(562, false, "管理员登录名已存在!"), 51 | ADMIN_NAME_NULL_ERROR(563, false, "管理员负责人不能为空!"), 52 | ADMIN_PASSWORD_ERROR(564, false, "密码不能为空后者两次输入不一致!"), 53 | ADMIN_CREATE_ERROR(565, false, "添加管理员失败!"), 54 | ADMIN_PASSWORD_NULL_ERROR(566, false, "密码不能为空!"), 55 | ADMIN_NOT_EXIT_ERROR(567, false, "管理员不存在或密码错误!"), 56 | ADMIN_FACE_NULL_ERROR(568, false, "人脸信息不能为空!"), 57 | ADMIN_FACE_LOGIN_ERROR(569, false, "人脸识别失败,请重试!"), 58 | CATEGORY_EXIST_ERROR(570, false, "文章分类已存在,请换一个分类名!"), 59 | 60 | // 媒体中心 相关错误 58x 61 | ARTICLE_COVER_NOT_EXIST_ERROR(580, false, "文章封面不存在,请选择一个!"), 62 | ARTICLE_CATEGORY_NOT_EXIST_ERROR(581, false, "请选择正确的文章领域!"), 63 | ARTICLE_CREATE_ERROR(582, false, "创建文章失败,请重试或联系管理员!"), 64 | ARTICLE_QUERY_PARAMS_ERROR(583, false, "文章列表查询参数错误!"), 65 | ARTICLE_DELETE_ERROR(584, false, "文章删除失败!"), 66 | ARTICLE_WITHDRAW_ERROR(585, false, "文章撤回失败!"), 67 | ARTICLE_REVIEW_ERROR(585, false, "文章审核出错!"), 68 | ARTICLE_ALREADY_READ_ERROR(586, false, "文章重复阅读!"), 69 | 70 | // 人脸识别错误代码 71 | FACE_VERIFY_TYPE_ERROR(600, false, "人脸比对验证类型不正确!"), 72 | FACE_VERIFY_LOGIN_ERROR(601, false, "人脸登录失败!"), 73 | 74 | // 系统错误,未预期的错误 555 75 | SYSTEM_ERROR(555, false, "系统繁忙,请稍后再试!"), 76 | SYSTEM_OPERATION_ERROR(556, false, "操作失败,请重试或联系管理员"), 77 | SYSTEM_RESPONSE_NO_INFO(557, false, ""), 78 | SYSTEM_ERROR_GLOBAL(558, false, "全局降级:系统繁忙,请稍后再试!"), 79 | SYSTEM_ERROR_FEIGN(559, false, "客户端Feign降级:系统繁忙,请稍后再试!"), 80 | SYSTEM_ERROR_ZUUL(560, false, "请求系统过于繁忙,请稍后再试!"); 81 | 82 | 83 | // 响应业务状态 84 | private Integer status; 85 | // 调用是否成功 86 | private Boolean success; 87 | // 响应消息,可以为成功或者失败的消息 88 | private String msg; 89 | 90 | ResponseStatusEnum(Integer status, Boolean success, String msg) { 91 | this.status = status; 92 | this.success = success; 93 | this.msg = msg; 94 | } 95 | 96 | public Integer status() { 97 | return status; 98 | } 99 | public Boolean success() { 100 | return success; 101 | } 102 | public String msg() { 103 | return msg; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/utils/DesensitizationUtil.java: -------------------------------------------------------------------------------- 1 | package com.imooc.utils; 2 | 3 | /** 4 | * 通用脱敏工具类 5 | * 可用于: 6 | * 用户名 7 | * 手机号 8 | * 邮箱 9 | * 地址等 10 | */ 11 | public class DesensitizationUtil { 12 | 13 | private static final int SIZE = 6; 14 | private static final String SYMBOL = "*"; 15 | 16 | public static void main(String[] args) { 17 | String name = commonDisplay("慕课网"); 18 | String mobile = commonDisplay("13900000000"); 19 | String mail = commonDisplay("admin@imooc.com"); 20 | String address = commonDisplay("北京大运河东路888号"); 21 | 22 | System.out.println(name); 23 | System.out.println(mobile); 24 | System.out.println(mail); 25 | System.out.println(address); 26 | } 27 | 28 | /** 29 | * 通用脱敏方法 30 | * @param value 31 | * @return 32 | */ 33 | public static String commonDisplay(String value) { 34 | if (null == value || "".equals(value)) { 35 | return value; 36 | } 37 | int len = value.length(); 38 | int pamaone = len / 2; 39 | int pamatwo = pamaone - 1; 40 | int pamathree = len % 2; 41 | StringBuilder stringBuilder = new StringBuilder(); 42 | if (len <= 2) { 43 | if (pamathree == 1) { 44 | return SYMBOL; 45 | } 46 | stringBuilder.append(SYMBOL); 47 | stringBuilder.append(value.charAt(len - 1)); 48 | } else { 49 | if (pamatwo <= 0) { 50 | stringBuilder.append(value.substring(0, 1)); 51 | stringBuilder.append(SYMBOL); 52 | stringBuilder.append(value.substring(len - 1, len)); 53 | 54 | } else if (pamatwo >= SIZE / 2 && SIZE + 1 != len) { 55 | int pamafive = (len - SIZE) / 2; 56 | stringBuilder.append(value.substring(0, pamafive)); 57 | for (int i = 0; i < SIZE; i++) { 58 | stringBuilder.append(SYMBOL); 59 | } 60 | if ((pamathree == 0 && SIZE / 2 == 0) || (pamathree != 0 && SIZE % 2 != 0)) { 61 | stringBuilder.append(value.substring(len - pamafive, len)); 62 | } else { 63 | stringBuilder.append(value.substring(len - (pamafive + 1), len)); 64 | } 65 | } else { 66 | int pamafour = len - 2; 67 | stringBuilder.append(value.substring(0, 1)); 68 | for (int i = 0; i < pamafour; i++) { 69 | stringBuilder.append(SYMBOL); 70 | } 71 | stringBuilder.append(value.substring(len - 1, len)); 72 | } 73 | } 74 | return stringBuilder.toString(); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/utils/IPUtil.java: -------------------------------------------------------------------------------- 1 | package com.imooc.utils; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | /** 6 | * 用户获得用户ip的工具类 7 | */ 8 | public class IPUtil { 9 | 10 | /** 11 | * 获取请求IP: 12 | * 用户的真实IP不能使用request.getRemoteAddr() 13 | * 这是因为可能会使用一些代理软件,这样ip获取就不准确了 14 | * 此外我们如果使用了多级(LVS/Nginx)反向代理的话,ip需要从X-Forwarded-For中获得第一个非unknown的IP才是用户的有效ip。 15 | * @param request 16 | * @return 17 | */ 18 | public static String getRequestIp(HttpServletRequest request) { 19 | String ip = request.getHeader("x-forwarded-for"); 20 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 21 | ip = request.getHeader("Proxy-Client-IP"); 22 | } 23 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 24 | ip = request.getHeader("WL-Proxy-Client-IP"); 25 | } 26 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 27 | ip = request.getHeader("HTTP_CLIENT_IP"); 28 | } 29 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 30 | ip = request.getHeader("HTTP_X_FORWARDED_FOR"); 31 | } 32 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 33 | ip = request.getRemoteAddr(); 34 | } 35 | return ip; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.imooc.utils; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.JavaType; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 11 | * @Title: JsonUtils.java 12 | * @Package com.imooc.utils 13 | * @Description: json转换类 14 | * Copyright: Copyright (c) 15 | * Company: www.imooc.com 16 | * 17 | * @author imooc 18 | */ 19 | public class JsonUtils { 20 | 21 | // 定义jackson对象 22 | private static final ObjectMapper MAPPER = new ObjectMapper(); 23 | 24 | /** 25 | * 将对象转换成json字符串。 26 | * @param data 27 | * @return 28 | */ 29 | public static String objectToJson(Object data) { 30 | try { 31 | String string = MAPPER.writeValueAsString(data); 32 | return string; 33 | } catch (JsonProcessingException e) { 34 | e.printStackTrace(); 35 | } 36 | return null; 37 | } 38 | 39 | /** 40 | * 将json结果集转化为对象 41 | * 42 | * @param jsonData json数据 43 | * @param beanType 对象中的object类型 44 | * @return 45 | */ 46 | public static T jsonToPojo(String jsonData, Class beanType) { 47 | try { 48 | T t = MAPPER.readValue(jsonData, beanType); 49 | return t; 50 | } catch (Exception e) { 51 | e.printStackTrace(); 52 | } 53 | return null; 54 | } 55 | 56 | /** 57 | * 将json数据转换成pojo对象list 58 | * @param jsonData 59 | * @param beanType 60 | * @return 61 | */ 62 | public static List jsonToList(String jsonData, Class beanType) { 63 | JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType); 64 | try { 65 | List list = MAPPER.readValue(jsonData, javaType); 66 | return list; 67 | } catch (Exception e) { 68 | e.printStackTrace(); 69 | } 70 | 71 | return null; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/utils/MyInfo.java: -------------------------------------------------------------------------------- 1 | package com.imooc.utils; 2 | 3 | public class MyInfo { 4 | 5 | public static String getMobile() { 6 | return ""; 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/utils/PagedGridResult.java: -------------------------------------------------------------------------------- 1 | package com.imooc.utils; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 7 | * @Title: PagedGridResult.java 8 | * @Package com.imooc.utils 9 | * @Description: 用来返回分页Grid的数据格式 10 | * Copyright: Copyright (c) 2021 11 | */ 12 | public class PagedGridResult { 13 | 14 | private int page; // 当前页数 15 | private long total; // 总页数 16 | private long records; // 总记录数 17 | private List rows; // 每行显示的内容 18 | 19 | public int getPage() { 20 | return page; 21 | } 22 | public void setPage(int page) { 23 | this.page = page; 24 | } 25 | 26 | public long getTotal() { 27 | return total; 28 | } 29 | 30 | public void setTotal(long total) { 31 | this.total = total; 32 | } 33 | 34 | public void setTotal(int total) { 35 | this.total = total; 36 | } 37 | public long getRecords() { 38 | return records; 39 | } 40 | public void setRecords(long records) { 41 | this.records = records; 42 | } 43 | public List getRows() { 44 | return rows; 45 | } 46 | public void setRows(List rows) { 47 | this.rows = rows; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/utils/SMSUtils.java: -------------------------------------------------------------------------------- 1 | package com.imooc.utils; 2 | 3 | import com.tencentcloudapi.common.Credential; 4 | import com.tencentcloudapi.common.exception.TencentCloudSDKException; 5 | import com.tencentcloudapi.common.profile.ClientProfile; 6 | import com.tencentcloudapi.common.profile.HttpProfile; 7 | import com.tencentcloudapi.sms.v20210111.SmsClient; 8 | import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest; 9 | import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | public class SMSUtils { 15 | @Autowired 16 | private TencentCloudProperties tencentCloudProperties; 17 | 18 | public void sendSMS(String phone, String code) throws Exception { 19 | try { 20 | /* 必要步骤: 21 | * 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。 22 | * 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。 23 | * 你也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人, 24 | * 以免泄露密钥对危及你的财产安全。 25 | * CAM密匙查询获取: https://console.cloud.tencent.com/cam/capi*/ 26 | Credential cred = new Credential(tencentCloudProperties.getSecretId(), 27 | tencentCloudProperties.getSecretKey()); 28 | 29 | // 实例化一个http选项,可选的,没有特殊需求可以跳过 30 | HttpProfile httpProfile = new HttpProfile(); 31 | 32 | // httpProfile.setReqMethod("POST"); // 默认使用POST 33 | 34 | /* SDK会自动指定域名。通常是不需要特地指定域名的,但是如果你访问的是金融区的服务 35 | * 则必须手动指定域名,例如sms的上海金融区域名: sms.ap-shanghai-fsi.tencentcloudapi.com */ 36 | httpProfile.setEndpoint("sms.tencentcloudapi.com"); 37 | 38 | // 实例化一个client选项 39 | ClientProfile clientProfile = new ClientProfile(); 40 | clientProfile.setHttpProfile(httpProfile); 41 | // 实例化要请求产品的client对象,clientProfile是可选的 42 | SmsClient client = new SmsClient(cred, "ap-nanjing", clientProfile); 43 | 44 | // 实例化一个请求对象,每个接口都会对应一个request对象 45 | SendSmsRequest req = new SendSmsRequest(); 46 | String[] phoneNumberSet1 = {"+86" + phone};//电话号码 47 | req.setPhoneNumberSet(phoneNumberSet1); 48 | req.setSmsSdkAppId("1400822965"); // 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId 49 | req.setSignName("我们更爱保持沉默公众号"); // 签名 50 | req.setTemplateId("1802516"); // 模板id:必须填写已审核通过的模板 ID。模板ID可登录 [短信控制台] 查看 51 | 52 | /* 模板参数(自定义占位变量): 若无模板参数,则设置为空 */ 53 | String[] templateParamSet1 = {code}; 54 | req.setTemplateParamSet(templateParamSet1); 55 | 56 | // 返回的resp是一个SendSmsResponse的实例,与请求对象对应 57 | SendSmsResponse resp = client.SendSms(req); 58 | // 输出json格式的字符串回包 59 | // System.out.println(SendSmsResponse.toJsonString(resp)); 60 | } catch (TencentCloudSDKException e) { 61 | System.out.println(e.toString()); 62 | } 63 | } 64 | 65 | public static void main(String[] args) { 66 | try { 67 | new SMSUtils().sendSMS("15237439161", "7896"); 68 | } catch (Exception e) { 69 | e.printStackTrace(); 70 | } 71 | } 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /book-common/src/main/java/com/imooc/utils/TencentCloudProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.utils; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.PropertySource; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * @author vercen 10 | * @version 1.0 11 | * @date 2023/5/25 10:21 12 | * 获取短信配置 13 | */ 14 | @Component 15 | @Data 16 | @PropertySource("classpath:tencentcloud.properties") 17 | @ConfigurationProperties(prefix = "tencent.cloud") 18 | public class TencentCloudProperties { 19 | 20 | private String secretId; 21 | private String secretKey; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/Code.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | import org.n3r.idworker.strategy.DefaultRandomCodeStrategy; 4 | 5 | public class Code { 6 | private static RandomCodeStrategy strategy; 7 | 8 | static { 9 | RandomCodeStrategy strategy = new DefaultRandomCodeStrategy(); 10 | strategy.init(); 11 | configure(strategy); 12 | } 13 | 14 | public static synchronized void configure(RandomCodeStrategy custom) { 15 | if (strategy == custom) return; 16 | if (strategy != null) strategy.release(); 17 | 18 | strategy = custom; 19 | } 20 | 21 | /** 22 | * Next Unique code. 23 | * The max length will be 1024-Integer.MAX-Integer.MAX(2147483647) which has 4+10+10+2*1=26 characters. 24 | * The min length will be 0-0. 25 | * 26 | * @return unique string code. 27 | */ 28 | public static synchronized String next() { 29 | long workerId = Id.getWorkerId(); 30 | int prefix = strategy.prefix(); 31 | int next = strategy.next(); 32 | 33 | return String.format("%d-%03d-%06d", workerId, prefix, next); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/DayCode.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | import org.n3r.idworker.strategy.DayPrefixRandomCodeStrategy; 4 | 5 | public class DayCode { 6 | static RandomCodeStrategy strategy; 7 | 8 | static { 9 | DayPrefixRandomCodeStrategy dayPrefixCodeStrategy = new DayPrefixRandomCodeStrategy("yyMM"); 10 | dayPrefixCodeStrategy.setMinRandomSize(7); 11 | dayPrefixCodeStrategy.setMaxRandomSize(7); 12 | strategy = dayPrefixCodeStrategy; 13 | strategy.init(); 14 | } 15 | 16 | public static synchronized String next() { 17 | return String.format("%d-%04d-%07d", Id.getWorkerId(), strategy.prefix(), strategy.next()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/Id.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | import org.n3r.idworker.strategy.DefaultWorkerIdStrategy; 4 | 5 | public class Id { 6 | private static WorkerIdStrategy workerIdStrategy; 7 | private static IdWorker idWorker; 8 | 9 | static { 10 | configure(DefaultWorkerIdStrategy.instance); 11 | } 12 | 13 | public static synchronized void configure(WorkerIdStrategy custom) { 14 | if (workerIdStrategy == custom) return; 15 | 16 | if (workerIdStrategy != null) workerIdStrategy.release(); 17 | workerIdStrategy = custom; 18 | workerIdStrategy.initialize(); 19 | idWorker = new IdWorker(workerIdStrategy.availableWorkerId()); 20 | } 21 | 22 | public static long next() { 23 | return idWorker.nextId(); 24 | } 25 | 26 | public static long getWorkerId() { 27 | return idWorker.getWorkerId(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/IdWorker.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | import java.security.SecureRandom; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | public class IdWorker { 9 | protected long epoch = 1288834974657L; 10 | // protected long epoch = 1387886498127L; // 2013-12-24 20:01:38.127 11 | 12 | 13 | protected long workerIdBits = 10L; 14 | protected long maxWorkerId = -1L ^ (-1L << workerIdBits); 15 | protected long sequenceBits = 11L; 16 | 17 | protected long workerIdShift = sequenceBits; 18 | protected long timestampLeftShift = sequenceBits + workerIdBits; 19 | protected long sequenceMask = -1L ^ (-1L << sequenceBits); 20 | 21 | protected long lastMillis = -1L; 22 | 23 | protected final long workerId; 24 | protected long sequence = 0L; 25 | protected Logger logger = LoggerFactory.getLogger(IdWorker.class); 26 | 27 | public IdWorker(long workerId) { 28 | this.workerId = checkWorkerId(workerId); 29 | 30 | logger.debug("worker starting. timestamp left shift {}, worker id {}", timestampLeftShift, workerId); 31 | } 32 | 33 | public long getEpoch() { 34 | return epoch; 35 | } 36 | 37 | private long checkWorkerId(long workerId) { 38 | // sanity check for workerId 39 | if (workerId > maxWorkerId || workerId < 0) { 40 | int rand = new SecureRandom().nextInt((int) maxWorkerId + 1); 41 | logger.warn("worker Id can't be greater than {} or less than 0, use a random {}", maxWorkerId, rand); 42 | return rand; 43 | } 44 | 45 | return workerId; 46 | } 47 | 48 | public synchronized long nextId() { 49 | long timestamp = millisGen(); 50 | 51 | if (timestamp < lastMillis) { 52 | logger.error("clock is moving backwards. Rejecting requests until {}.", lastMillis); 53 | throw new InvalidSystemClock(String.format( 54 | "Clock moved backwards. Refusing to generate id for {} milliseconds", lastMillis - timestamp)); 55 | } 56 | 57 | if (lastMillis == timestamp) { 58 | sequence = (sequence + 1) & sequenceMask; 59 | if (sequence == 0) 60 | timestamp = tilNextMillis(lastMillis); 61 | } else { 62 | sequence = 0; 63 | } 64 | 65 | lastMillis = timestamp; 66 | long diff = timestamp - getEpoch(); 67 | return (diff << timestampLeftShift) | 68 | (workerId << workerIdShift) | 69 | sequence; 70 | } 71 | 72 | protected long tilNextMillis(long lastMillis) { 73 | long millis = millisGen(); 74 | while (millis <= lastMillis) 75 | millis = millisGen(); 76 | 77 | return millis; 78 | } 79 | 80 | protected long millisGen() { 81 | return System.currentTimeMillis(); 82 | } 83 | 84 | public long getLastMillis() { 85 | return lastMillis; 86 | } 87 | 88 | public long getWorkerId() { 89 | return workerId; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/InvalidSystemClock.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | public class InvalidSystemClock extends RuntimeException { 4 | public InvalidSystemClock(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/RandomCodeStrategy.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | public interface RandomCodeStrategy { 4 | void init(); 5 | 6 | int prefix(); 7 | 8 | int next(); 9 | 10 | void release(); 11 | } 12 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/Sid.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | import org.n3r.idworker.strategy.DefaultWorkerIdStrategy; 4 | import org.n3r.idworker.utils.Utils; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | 10 | @Component 11 | public class Sid { 12 | private static WorkerIdStrategy workerIdStrategy; 13 | private static IdWorker idWorker; 14 | 15 | static { 16 | configure(DefaultWorkerIdStrategy.instance); 17 | } 18 | 19 | 20 | public static synchronized void configure(WorkerIdStrategy custom) { 21 | if (workerIdStrategy != null) { 22 | workerIdStrategy.release(); 23 | } 24 | workerIdStrategy = custom; 25 | idWorker = new IdWorker(workerIdStrategy.availableWorkerId()) { 26 | @Override 27 | public long getEpoch() { 28 | return Utils.midnightMillis(); 29 | } 30 | }; 31 | } 32 | 33 | /** 34 | * 一天最大毫秒86400000,最大占用27比特 35 | * 27+10+11=48位 最大值281474976710655(15字),YK0XXHZ827(10字) 36 | * 6位(YYMMDD)+15位,共21位 37 | * 38 | * @return 固定21位数字字符串 39 | */ 40 | 41 | public static String next() { 42 | long id = idWorker.nextId(); 43 | String yyMMdd = new SimpleDateFormat("yyMMdd").format(new Date()); 44 | return yyMMdd + String.format("%014d", id); 45 | } 46 | 47 | 48 | /** 49 | * 返回固定16位的字母数字混编的字符串。 50 | */ 51 | public String nextShort() { 52 | long id = idWorker.nextId(); 53 | String yyMMdd = new SimpleDateFormat("yyMMdd").format(new Date()); 54 | return yyMMdd + Utils.padLeft(Utils.encode(id), 10, '0'); 55 | } 56 | 57 | public static void main(String[] args) { 58 | String aa = new Sid().nextShort(); 59 | String bb = new Sid().next(); 60 | 61 | System.out.println(aa); 62 | System.out.println(bb); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/Test.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | public class Test { 4 | 5 | public static void main(String[] args) { 6 | 7 | for (int i = 0 ; i < 1000 ; i ++) { 8 | // System.out.println(Sid.nextShort()); 9 | } 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/WorkerIdStrategy.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | public interface WorkerIdStrategy { 4 | void initialize(); 5 | 6 | long availableWorkerId(); 7 | 8 | void release(); 9 | } 10 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/strategy/DayPrefixRandomCodeStrategy.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.strategy; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class DayPrefixRandomCodeStrategy extends DefaultRandomCodeStrategy { 7 | private final String dayFormat; 8 | private String lastDay; 9 | 10 | public DayPrefixRandomCodeStrategy(String dayFormat) { 11 | this.dayFormat = dayFormat; 12 | } 13 | 14 | @Override 15 | public void init() { 16 | String day = createDate(); 17 | if (day.equals(lastDay)) 18 | throw new RuntimeException("init failed for day unrolled"); 19 | 20 | lastDay = day; 21 | 22 | availableCodes.clear(); 23 | release(); 24 | 25 | prefixIndex = Integer.parseInt(lastDay); 26 | if (tryUsePrefix()) return; 27 | 28 | throw new RuntimeException("prefix is not available " + prefixIndex); 29 | } 30 | 31 | private String createDate() { 32 | return new SimpleDateFormat(dayFormat).format(new Date()); 33 | } 34 | 35 | @Override 36 | public int next() { 37 | if (!lastDay.equals(createDate())) init(); 38 | 39 | return super.next(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/strategy/DefaultRandomCodeStrategy.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.strategy; 2 | 3 | import org.n3r.idworker.Id; 4 | import org.n3r.idworker.RandomCodeStrategy; 5 | import org.n3r.idworker.utils.Utils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.security.SecureRandom; 12 | import java.util.ArrayDeque; 13 | import java.util.BitSet; 14 | import java.util.Queue; 15 | 16 | public class DefaultRandomCodeStrategy implements RandomCodeStrategy { 17 | public static final int MAX_BITS = 1000000; 18 | 19 | Logger log = LoggerFactory.getLogger(DefaultRandomCodeStrategy.class); 20 | 21 | File idWorkerHome = Utils.createIdWorkerHome(); 22 | volatile FileLock fileLock; 23 | BitSet codesFilter; 24 | 25 | int prefixIndex = -1; 26 | File codePrefixIndex; 27 | 28 | int minRandomSize = 6; 29 | int maxRandomSize = 6; 30 | 31 | public DefaultRandomCodeStrategy() { 32 | destroyFileLockWhenShutdown(); 33 | } 34 | 35 | @Override 36 | public void init() { 37 | release(); 38 | 39 | while (++prefixIndex < 1000) { 40 | if (tryUsePrefix()) return; 41 | } 42 | 43 | throw new RuntimeException("all prefixes are used up, the world maybe ends!"); 44 | } 45 | 46 | public DefaultRandomCodeStrategy setMinRandomSize(int minRandomSize) { 47 | this.minRandomSize = minRandomSize; 48 | return this; 49 | } 50 | 51 | public DefaultRandomCodeStrategy setMaxRandomSize(int maxRandomSize) { 52 | this.maxRandomSize = maxRandomSize; 53 | return this; 54 | } 55 | 56 | protected boolean tryUsePrefix() { 57 | codePrefixIndex = new File(idWorkerHome, Id.getWorkerId() + ".code.prefix." + prefixIndex); 58 | 59 | if (!createPrefixIndexFile()) return false; 60 | if (!createFileLock()) return false; 61 | if (!createBloomFilter()) return false; 62 | 63 | log.info("get available prefix index file {}", codePrefixIndex); 64 | 65 | return true; 66 | } 67 | 68 | private boolean createFileLock() { 69 | if (fileLock != null) fileLock.destroy(); 70 | fileLock = new FileLock(codePrefixIndex); 71 | return fileLock.tryLock(); 72 | } 73 | 74 | private boolean createBloomFilter() { 75 | codesFilter = fileLock.readObject(); 76 | if (codesFilter == null) { 77 | log.info("create new bloom filter"); 78 | codesFilter = new BitSet(MAX_BITS); // 2^24 79 | } else { 80 | int size = codesFilter.cardinality(); 81 | if (size >= MAX_BITS) { 82 | log.warn("bloom filter with prefix file {} is already full", codePrefixIndex); 83 | return false; 84 | } 85 | log.info("recreate bloom filter with cardinality {}", size); 86 | } 87 | 88 | return true; 89 | } 90 | 91 | private void destroyFileLockWhenShutdown() { 92 | Runtime.getRuntime().addShutdownHook(new Thread() { 93 | @Override 94 | public void run() { 95 | release(); 96 | } 97 | }); 98 | } 99 | 100 | private boolean createPrefixIndexFile() { 101 | try { 102 | codePrefixIndex.createNewFile(); 103 | return codePrefixIndex.exists(); 104 | } catch (IOException e) { 105 | e.printStackTrace(); 106 | log.warn("create file {} error {}", codePrefixIndex, e.getMessage()); 107 | } 108 | return false; 109 | } 110 | 111 | @Override 112 | public int prefix() { 113 | return prefixIndex; 114 | } 115 | 116 | static final int CACHE_CODES_NUM = 1000; 117 | 118 | SecureRandom secureRandom = new SecureRandom(); 119 | Queue availableCodes = new ArrayDeque(CACHE_CODES_NUM); 120 | 121 | @Override 122 | public int next() { 123 | if (availableCodes.isEmpty()) generate(); 124 | 125 | return availableCodes.poll(); 126 | } 127 | 128 | @Override 129 | public synchronized void release() { 130 | if (fileLock != null) { 131 | fileLock.writeObject(codesFilter); 132 | fileLock.destroy(); 133 | fileLock = null; 134 | } 135 | } 136 | 137 | private void generate() { 138 | for (int i = 0; i < CACHE_CODES_NUM; ++i) 139 | availableCodes.add(generateOne()); 140 | 141 | fileLock.writeObject(codesFilter); 142 | } 143 | 144 | private int generateOne() { 145 | while (true) { 146 | int code = secureRandom.nextInt(max(maxRandomSize)); 147 | boolean existed = contains(code); 148 | 149 | code = !existed ? add(code) : tryFindAvailableCode(code); 150 | if (code >= 0) return code; 151 | 152 | init(); 153 | } 154 | } 155 | 156 | private int tryFindAvailableCode(int code) { 157 | int next = codesFilter.nextClearBit(code); 158 | if (next != -1 && next < max(maxRandomSize)) return add(next); 159 | 160 | next = codesFilter.previousClearBit(code); 161 | if (next != -1) return add(next); 162 | 163 | return -1; 164 | } 165 | 166 | private int add(int code) { 167 | codesFilter.set(code); 168 | return code; 169 | } 170 | 171 | private boolean contains(int code) { 172 | return codesFilter.get(code); 173 | } 174 | 175 | 176 | private int max(int size) { 177 | switch (size) { 178 | case 1: // fall through 179 | case 2: // fall through 180 | case 3: // fall through 181 | case 4: 182 | return 10000; 183 | case 5: 184 | return 100000; 185 | case 6: 186 | return 1000000; 187 | case 7: 188 | return 10000000; 189 | case 8: 190 | return 100000000; 191 | case 9: 192 | return 1000000000; 193 | default: 194 | return Integer.MAX_VALUE; 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/strategy/DefaultWorkerIdStrategy.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.strategy; 2 | 3 | import org.n3r.idworker.WorkerIdStrategy; 4 | import org.n3r.idworker.utils.HttpReq; 5 | import org.n3r.idworker.utils.Ip; 6 | import org.n3r.idworker.utils.Props; 7 | import org.n3r.idworker.utils.Utils; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.io.File; 12 | import java.io.IOException; 13 | import java.security.SecureRandom; 14 | import java.util.Properties; 15 | import java.util.Random; 16 | 17 | public class DefaultWorkerIdStrategy implements WorkerIdStrategy { 18 | static long workerIdBits = 10L; 19 | static long maxWorkerId = -1L ^ (-1L << workerIdBits); 20 | static Random random = new SecureRandom(); 21 | 22 | public static final WorkerIdStrategy instance = new DefaultWorkerIdStrategy(); 23 | 24 | private final Properties props = 25 | Props.tryProperties("idworker-client.properties", Utils.DOT_IDWORKERS); 26 | private final String idWorkerServerUrl = 27 | props.getProperty("server.address", "http://id.worker.server:18001"); 28 | 29 | String userName = System.getProperty("user.name"); 30 | 31 | String ipDotUsername = Ip.ip + "." + userName; 32 | String ipudotlock = ipDotUsername + ".lock."; 33 | int workerIdIndex = ipudotlock.length(); 34 | long workerId; 35 | FileLock fileLock; 36 | 37 | Logger logger = LoggerFactory.getLogger(DefaultWorkerIdStrategy.class); 38 | private boolean inited; 39 | 40 | 41 | private void init() { 42 | workerId = findAvailWorkerId(); 43 | if (workerId >= 0) { 44 | destroyFileLockWhenShutdown(); 45 | startSyncThread(); 46 | } else { 47 | syncWithWorkerIdServer(); 48 | workerId = findAvailWorkerId(); 49 | if (workerId < 0) workerId = increaseWithWorkerIdServer(); 50 | } 51 | 52 | if (workerId < 0) workerId = tryToCreateOnIp(); 53 | if (workerId < 0) { 54 | logger.warn("DANGEROUS!!! Try to use random worker id."); 55 | workerId = tryToRandomOnIp(); // Try avoiding! it could cause duplicated 56 | } 57 | 58 | if (workerId < 0) { 59 | logger.warn("the world may be ended!"); 60 | throw new RuntimeException("the world may be ended"); 61 | } 62 | } 63 | 64 | private void destroyFileLockWhenShutdown() { 65 | Runtime.getRuntime().addShutdownHook(new Thread() { 66 | @Override 67 | public void run() { 68 | fileLock.destroy(); 69 | } 70 | }); 71 | } 72 | 73 | private void startSyncThread() { 74 | new Thread() { 75 | @Override 76 | public void run() { 77 | syncWithWorkerIdServer(); 78 | } 79 | }.start(); 80 | } 81 | 82 | private long increaseWithWorkerIdServer() { 83 | String incId = HttpReq.get(idWorkerServerUrl) 84 | .req("/inc") 85 | .param("ipu", ipDotUsername) 86 | .exec(); 87 | if (incId == null || incId.trim().isEmpty()) return -1L; 88 | 89 | long lid = Long.parseLong(incId); 90 | 91 | return checkAvail(lid); 92 | } 93 | 94 | private long tryToCreateOnIp() { 95 | long wid = Ip.lip & maxWorkerId; 96 | 97 | return checkAvail(wid); 98 | } 99 | 100 | private long tryToRandomOnIp() { 101 | long avaiWorkerId = -1L; 102 | long tryTimes = -1; 103 | 104 | while (avaiWorkerId < 0 && ++tryTimes < maxWorkerId) { 105 | long wid = Ip.lip & random.nextInt((int) maxWorkerId); 106 | 107 | avaiWorkerId = checkAvail(wid); 108 | } 109 | return avaiWorkerId; 110 | } 111 | 112 | private long checkAvail(long wid) { 113 | long availWorkerId = -1L; 114 | try { 115 | File idWorkerHome = Utils.createIdWorkerHome(); 116 | new File(idWorkerHome, ipudotlock + String.format("%04d", wid)).createNewFile(); 117 | availWorkerId = findAvailWorkerId(); 118 | } catch (IOException e) { 119 | logger.warn("checkAvail error", e); 120 | } 121 | 122 | return availWorkerId; 123 | } 124 | 125 | private void syncWithWorkerIdServer() { 126 | String syncIds = HttpReq.get(idWorkerServerUrl).req("/sync") 127 | .param("ipu", ipDotUsername).param("ids", buildWorkerIdsOfCurrentIp()) 128 | .exec(); 129 | if (syncIds == null || syncIds.trim().isEmpty()) return; 130 | 131 | String[] syncIdsArr = syncIds.split(","); 132 | File idWorkerHome = Utils.createIdWorkerHome(); 133 | for (String syncId : syncIdsArr) { 134 | try { 135 | new File(idWorkerHome, ipudotlock + syncId).createNewFile(); 136 | } catch (IOException e) { 137 | logger.warn("create workerid lock file error", e); 138 | } 139 | } 140 | } 141 | 142 | private String buildWorkerIdsOfCurrentIp() { 143 | StringBuilder sb = new StringBuilder(); 144 | File idWorkerHome = Utils.createIdWorkerHome(); 145 | for (File lockFile : idWorkerHome.listFiles()) { 146 | // check the format like 10.142.1.151.lock.0001 147 | if (!lockFile.getName().startsWith(ipudotlock)) continue; 148 | 149 | String workerId = lockFile.getName().substring(workerIdIndex); 150 | if (!workerId.matches("\\d\\d\\d\\d")) continue; 151 | 152 | if (sb.length() > 0) sb.append(','); 153 | sb.append(workerId); 154 | } 155 | 156 | return sb.toString(); 157 | } 158 | 159 | 160 | /** 161 | * Find the local available worker id. 162 | * 163 | * @return -1 when N/A 164 | */ 165 | private long findAvailWorkerId() { 166 | File idWorkerHome = Utils.createIdWorkerHome(); 167 | 168 | for (File lockFile : idWorkerHome.listFiles()) { 169 | // check the format like 10.142.1.151.lock.0001 170 | if (!lockFile.getName().startsWith(ipudotlock)) continue; 171 | 172 | String workerId = lockFile.getName().substring(workerIdIndex); 173 | if (!workerId.matches("\\d\\d\\d\\d")) continue; 174 | 175 | FileLock fileLock = new FileLock(lockFile); 176 | if (!fileLock.tryLock()) { 177 | fileLock.destroy(); 178 | continue; 179 | } 180 | 181 | this.fileLock = fileLock; 182 | return Long.parseLong(workerId); 183 | } 184 | 185 | return -1; 186 | } 187 | 188 | @Override 189 | public void initialize() { 190 | if (inited) return; 191 | init(); 192 | this.inited = true; 193 | } 194 | 195 | @Override 196 | public long availableWorkerId() { 197 | return workerId; 198 | } 199 | 200 | @Override 201 | public void release() { 202 | if (fileLock != null) fileLock.destroy(); 203 | inited = false; 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/strategy/FileLock.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.strategy; 2 | 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.*; 8 | import java.nio.channels.Channels; 9 | import java.nio.channels.ClosedChannelException; 10 | import java.nio.channels.FileChannel; 11 | import java.nio.channels.OverlappingFileLockException; 12 | 13 | /** 14 | * A file lock a la flock/funlock 15 | *

16 | * The given path will be created and opened if it doesn't exist. 17 | */ 18 | public class FileLock { 19 | private final File file; 20 | private FileChannel channel; 21 | private java.nio.channels.FileLock flock = null; 22 | Logger logger = LoggerFactory.getLogger(FileLock.class); 23 | 24 | public FileLock(File file) { 25 | this.file = file; 26 | 27 | try { 28 | file.createNewFile(); // create the file if it doesn't exist 29 | channel = new RandomAccessFile(file, "rw").getChannel(); 30 | } catch (IOException e) { 31 | throw new RuntimeException(e); 32 | } 33 | } 34 | 35 | 36 | /** 37 | * Lock the file or throw an exception if the lock is already held 38 | */ 39 | public void lock() { 40 | try { 41 | synchronized (this) { 42 | logger.trace("Acquiring lock on {}", file.getAbsolutePath()); 43 | flock = channel.lock(); 44 | } 45 | } catch (IOException e) { 46 | throw new RuntimeException(e); 47 | } 48 | } 49 | 50 | /** 51 | * Try to lock the file and return true if the locking succeeds 52 | */ 53 | public boolean tryLock() { 54 | synchronized (this) { 55 | logger.trace("Acquiring lock on {}", file.getAbsolutePath()); 56 | try { 57 | // weirdly this method will return null if the lock is held by another 58 | // process, but will throw an exception if the lock is held by this process 59 | // so we have to handle both cases 60 | flock = channel.tryLock(); 61 | return flock != null; 62 | } catch (OverlappingFileLockException e) { 63 | return false; 64 | } catch (IOException e) { 65 | throw new RuntimeException(e); 66 | } 67 | } 68 | } 69 | 70 | /** 71 | * Unlock the lock if it is held 72 | */ 73 | public void unlock() { 74 | synchronized (this) { 75 | logger.trace("Releasing lock on {}", file.getAbsolutePath()); 76 | if (flock == null) return; 77 | try { 78 | flock.release(); 79 | } catch (ClosedChannelException e) { 80 | // Ignore 81 | } catch (IOException e) { 82 | throw new RuntimeException(e); 83 | } 84 | } 85 | } 86 | 87 | /** 88 | * Destroy this lock, closing the associated FileChannel 89 | */ 90 | public void destroy() { 91 | synchronized (this) { 92 | unlock(); 93 | if (!channel.isOpen()) return; 94 | 95 | try { 96 | channel.close(); 97 | } catch (IOException e) { 98 | throw new RuntimeException(e); 99 | } 100 | } 101 | } 102 | 103 | 104 | @SuppressWarnings("unchecked") 105 | public T readObject() { 106 | try { 107 | InputStream is = Channels.newInputStream(channel); 108 | ObjectInputStream objectReader = new ObjectInputStream(is); 109 | return (T) objectReader.readObject(); 110 | } catch (EOFException e) { 111 | } catch (Exception e) { 112 | throw new RuntimeException(e); 113 | } 114 | 115 | return null; 116 | } 117 | 118 | 119 | public synchronized boolean writeObject(Object object) { 120 | if (!channel.isOpen()) return false; 121 | 122 | try { 123 | channel.position(0); 124 | OutputStream out = Channels.newOutputStream(channel); 125 | ObjectOutputStream objectOutput = new ObjectOutputStream(out); 126 | objectOutput.writeObject(object); 127 | return true; 128 | } catch (Exception e) { 129 | throw new RuntimeException(e); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/utils/HttpReq.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.utils; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.UnsupportedEncodingException; 10 | import java.net.*; 11 | 12 | public class HttpReq { 13 | private final String baseUrl; 14 | private String req; 15 | private StringBuilder params = new StringBuilder(); 16 | Logger logger = LoggerFactory.getLogger(HttpReq.class); 17 | 18 | public HttpReq(String baseUrl) { 19 | this.baseUrl = baseUrl; 20 | } 21 | 22 | public static HttpReq get(String baseUrl) { 23 | return new HttpReq(baseUrl); 24 | } 25 | 26 | public HttpReq req(String req) { 27 | this.req = req; 28 | return this; 29 | } 30 | 31 | public HttpReq param(String name, String value) { 32 | if (params.length() > 0) params.append('&'); 33 | try { 34 | params.append(name).append('=').append(URLEncoder.encode(value, "UTF-8")); 35 | } catch (UnsupportedEncodingException e) { 36 | throw new RuntimeException(e); 37 | } 38 | 39 | return this; 40 | } 41 | 42 | public String exec() { 43 | HttpURLConnection http = null; 44 | try { 45 | http = (HttpURLConnection) new URL(baseUrl 46 | + (req == null ? "" : req) 47 | + (params.length() > 0 ? ("?" + params) : "")).openConnection(); 48 | http.setRequestProperty("Accept-Charset", "UTF-8"); 49 | HttpURLConnection.setFollowRedirects(false); 50 | http.setConnectTimeout(5 * 1000); 51 | http.setReadTimeout(5 * 1000); 52 | http.connect(); 53 | 54 | int status = http.getResponseCode(); 55 | String charset = getCharset(http.getHeaderField("Content-Type")); 56 | 57 | if (status == 200) { 58 | return readResponseBody(http, charset); 59 | } else { 60 | logger.warn("non 200 respoonse :" + readErrorResponseBody(http, status, charset)); 61 | return null; 62 | } 63 | } catch (Exception e) { 64 | logger.error("exec error {}", e.getMessage()); 65 | return null; 66 | } finally { 67 | if (http != null) http.disconnect(); 68 | } 69 | 70 | } 71 | 72 | private static String readErrorResponseBody(HttpURLConnection http, int status, String charset) throws IOException { 73 | InputStream errorStream = http.getErrorStream(); 74 | if (errorStream != null) { 75 | String error = toString(charset, errorStream); 76 | return ("STATUS CODE =" + status + "\n\n" + error); 77 | } else { 78 | return ("STATUS CODE =" + status); 79 | } 80 | } 81 | 82 | private static String readResponseBody(HttpURLConnection http, String charset) throws IOException { 83 | InputStream inputStream = http.getInputStream(); 84 | 85 | return toString(charset, inputStream); 86 | } 87 | 88 | private static String toString(String charset, InputStream inputStream) throws IOException { 89 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 90 | byte[] buffer = new byte[1024]; 91 | 92 | int length; 93 | while ((length = inputStream.read(buffer)) != -1) { 94 | baos.write(buffer, 0, length); 95 | } 96 | 97 | return new String(baos.toByteArray(), charset); 98 | } 99 | 100 | private static String getCharset(String contentType) { 101 | if (contentType == null) return "UTF-8"; 102 | 103 | String charset = null; 104 | for (String param : contentType.replace(" ", "").split(";")) { 105 | if (param.startsWith("charset=")) { 106 | charset = param.split("=", 2)[1]; 107 | break; 108 | } 109 | } 110 | 111 | return charset == null ? "UTF-8" : charset; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/utils/IPv4Utils.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.utils; 2 | 3 | /** 4 | * This utility provides methods to either convert an IPv4 address to its long format or a 32bit dotted format. 5 | * 6 | * @author Aion 7 | * Created on 22/11/12 8 | */ 9 | public class IPv4Utils { 10 | 11 | /** 12 | * Returns the long format of the provided IP address. 13 | * 14 | * @param ipAddress the IP address 15 | * @return the long format of ipAddress 16 | * @throws IllegalArgumentException if ipAddress is invalid 17 | */ 18 | public static long toLong(String ipAddress) { 19 | if (ipAddress == null || ipAddress.isEmpty()) { 20 | throw new IllegalArgumentException("ip address cannot be null or empty"); 21 | } 22 | String[] octets = ipAddress.split(java.util.regex.Pattern.quote(".")); 23 | if (octets.length != 4) { 24 | throw new IllegalArgumentException("invalid ip address"); 25 | } 26 | long ip = 0; 27 | for (int i = 3; i >= 0; i--) { 28 | long octet = Long.parseLong(octets[3 - i]); 29 | if (octet > 255 || octet < 0) { 30 | throw new IllegalArgumentException("invalid ip address"); 31 | } 32 | ip |= octet << (i * 8); 33 | } 34 | return ip; 35 | } 36 | 37 | /** 38 | * Returns the 32bit dotted format of the provided long ip. 39 | * 40 | * @param ip the long ip 41 | * @return the 32bit dotted format of ip 42 | * @throws IllegalArgumentException if ip is invalid 43 | */ 44 | public static String toString(long ip) { 45 | // if ip is bigger than 255.255.255.255 or smaller than 0.0.0.0 46 | if (ip > 4294967295l || ip < 0) { 47 | throw new IllegalArgumentException("invalid ip"); 48 | } 49 | StringBuilder ipAddress = new StringBuilder(); 50 | for (int i = 3; i >= 0; i--) { 51 | int shift = i * 8; 52 | ipAddress.append((ip & (0xff << shift)) >> shift); 53 | if (i > 0) { 54 | ipAddress.append("."); 55 | } 56 | } 57 | return ipAddress.toString(); 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/utils/Ip.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.utils; 2 | 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.net.Inet4Address; 8 | import java.net.InetAddress; 9 | import java.net.NetworkInterface; 10 | import java.net.SocketException; 11 | import java.util.Enumeration; 12 | 13 | public class Ip { 14 | static Logger logger = LoggerFactory.getLogger(Ip.class); 15 | 16 | public static String ip; 17 | public static long lip; 18 | 19 | static { 20 | try { 21 | InetAddress localHostLANAddress = getFirstNonLoopbackAddress(); 22 | ip = localHostLANAddress.getHostAddress(); 23 | 24 | byte[] address = localHostLANAddress.getAddress(); 25 | lip = ((address [0] & 0xFFL) << (3*8)) + 26 | ((address [1] & 0xFFL) << (2*8)) + 27 | ((address [2] & 0xFFL) << (1*8)) + 28 | (address [3] & 0xFFL); 29 | } catch (Exception e) { 30 | logger.error("get ipv4 failed ", e); 31 | } 32 | } 33 | 34 | private static InetAddress getFirstNonLoopbackAddress() throws SocketException { 35 | Enumeration en = NetworkInterface.getNetworkInterfaces(); 36 | while (en.hasMoreElements()) { 37 | NetworkInterface i = (NetworkInterface) en.nextElement(); 38 | for (Enumeration en2 = i.getInetAddresses(); en2.hasMoreElements(); ) { 39 | InetAddress addr = (InetAddress) en2.nextElement(); 40 | if (addr.isLoopbackAddress()) continue; 41 | 42 | if (addr instanceof Inet4Address) { 43 | return addr; 44 | } 45 | } 46 | } 47 | return null; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/utils/Props.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.utils; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.*; 7 | import java.util.Properties; 8 | 9 | import static java.io.File.separator; 10 | import static org.n3r.idworker.utils.Serializes.closeQuietly; 11 | 12 | public class Props { 13 | static Logger log = LoggerFactory.getLogger(Props.class); 14 | 15 | public static Properties tryProperties(String propertiesFileName, String userHomeBasePath) { 16 | Properties properties = new Properties(); 17 | InputStream is = null; 18 | try { 19 | is = Props.tryResource(propertiesFileName, userHomeBasePath, Silent.ON); 20 | if (is != null) properties.load(is); 21 | } catch (IOException e) { 22 | log.error("load properties error: {}", e.getMessage()); 23 | } finally { 24 | closeQuietly(is); 25 | } 26 | 27 | return properties; 28 | } 29 | 30 | 31 | enum Silent {ON, OFF} 32 | 33 | public static InputStream tryResource(String propertiesFileName, String userHomeBasePath, Silent silent) { 34 | InputStream is = currentDirResource(new File(propertiesFileName)); 35 | if (is != null) return is; 36 | 37 | is = userHomeResource(propertiesFileName, userHomeBasePath); 38 | if (is != null) return is; 39 | 40 | is = classpathResource(propertiesFileName); 41 | if (is != null || silent == Silent.ON) return is; 42 | 43 | throw new RuntimeException("fail to find " + propertiesFileName + " in current dir or classpath"); 44 | } 45 | 46 | private static InputStream userHomeResource(String pathname, String appHome) { 47 | String filePath = System.getProperty("user.home") + separator + appHome; 48 | File dir = new File(filePath); 49 | if (!dir.exists()) return null; 50 | 51 | return currentDirResource(new File(dir, pathname)); 52 | } 53 | 54 | private static InputStream currentDirResource(File file) { 55 | if (!file.exists()) return null; 56 | 57 | try { 58 | return new FileInputStream(file); 59 | } catch (FileNotFoundException e) { 60 | // This should not happened 61 | log.error("read file {} error", file, e); 62 | return null; 63 | } 64 | } 65 | 66 | public static InputStream classpathResource(String resourceName) { 67 | return Props.class.getClassLoader().getResourceAsStream(resourceName); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/utils/Serializes.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.utils; 2 | 3 | import java.io.*; 4 | import java.nio.channels.FileChannel; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class Serializes { 9 | 10 | @SuppressWarnings("unchecked") 11 | public static List readObjects(File file) { 12 | ArrayList objects = new ArrayList(); 13 | ObjectInputStream objectReader = null; 14 | FileInputStream fis = null; 15 | try { 16 | fis = new FileInputStream(file); 17 | objectReader = new ObjectInputStream(fis); 18 | while (true) 19 | objects.add((T) objectReader.readObject()); 20 | 21 | } catch (EOFException e) { 22 | } catch (Exception e) { 23 | throw new RuntimeException(e); 24 | } finally { 25 | closeQuietly(objectReader); 26 | closeQuietly(fis); 27 | } 28 | 29 | return objects; 30 | } 31 | 32 | 33 | @SuppressWarnings("unchecked") 34 | public static T readObject(File file) { 35 | ObjectInputStream objectReader = null; 36 | FileInputStream fis = null; 37 | try { 38 | fis = new FileInputStream(file); 39 | objectReader = new ObjectInputStream(fis); 40 | return (T) objectReader.readObject(); 41 | 42 | } catch (EOFException e) { 43 | } catch (Exception e) { 44 | throw new RuntimeException(e); 45 | } finally { 46 | closeQuietly(objectReader); 47 | closeQuietly(fis); 48 | } 49 | 50 | return null; 51 | } 52 | 53 | public static void writeObject(File file, Object object) { 54 | ObjectOutputStream objectOutput = null; 55 | FileOutputStream fos = null; 56 | try { 57 | fos = new FileOutputStream(file); 58 | objectOutput = new ObjectOutputStream(fos); 59 | objectOutput.writeObject(object); 60 | } catch (Exception e) { 61 | throw new RuntimeException(e); 62 | } finally { 63 | closeQuietly(objectOutput); 64 | closeQuietly(fos); 65 | } 66 | } 67 | 68 | public static void writeObject(FileOutputStream fos, Object object) { 69 | FileChannel channel = fos.getChannel(); 70 | if (!channel.isOpen()) throw new RuntimeException("channel is closed"); 71 | 72 | try { 73 | channel.position(0); 74 | ObjectOutputStream objectOutput = new ObjectOutputStream(fos); 75 | objectOutput.writeObject(object); 76 | fos.flush(); 77 | } catch (Exception e) { 78 | throw new RuntimeException(e); 79 | } finally { 80 | } 81 | } 82 | 83 | public static void writeObjects(File file, Object... objects) { 84 | ObjectOutputStream objectOutput = null; 85 | FileOutputStream fos = null; 86 | try { 87 | fos = new FileOutputStream(file); 88 | objectOutput = new ObjectOutputStream(fos); 89 | 90 | for (Object object : objects) 91 | objectOutput.writeObject(object); 92 | } catch (Exception e) { 93 | throw new RuntimeException(e); 94 | } finally { 95 | closeQuietly(objectOutput); 96 | closeQuietly(fos); 97 | } 98 | 99 | } 100 | 101 | public static void closeQuietly(OutputStream os) { 102 | if (os != null) try { 103 | os.close(); 104 | } catch (IOException e) { 105 | // ignore 106 | } 107 | } 108 | 109 | 110 | public static void closeQuietly(InputStream is) { 111 | if (is != null) try { 112 | is.close(); 113 | } catch (IOException e) { 114 | // ignore 115 | } 116 | 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /book-common/src/main/java/org/n3r/idworker/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.utils; 2 | 3 | import java.io.*; 4 | import java.sql.Timestamp; 5 | import java.text.SimpleDateFormat; 6 | import java.util.Calendar; 7 | 8 | public class Utils { 9 | 10 | public static final String DOT_IDWORKERS = ".idworkers"; 11 | 12 | public static ClassLoader getClassLoader() { 13 | ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 14 | return contextClassLoader != null ? contextClassLoader : Utils.class.getClassLoader(); 15 | } 16 | 17 | 18 | public static InputStream classResourceToStream(String resourceName) { 19 | return getClassLoader().getResourceAsStream(resourceName); 20 | } 21 | 22 | 23 | public static String firstLine(String classResourceName) { 24 | InputStream inputStream = null; 25 | try { 26 | inputStream = classResourceToStream(classResourceName); 27 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); 28 | 29 | return bufferedReader.readLine(); 30 | } catch (IOException e) { 31 | return null; 32 | } finally { 33 | if (inputStream != null) try { 34 | inputStream.close(); 35 | } catch (IOException e) { 36 | // ignore 37 | } 38 | } 39 | } 40 | 41 | public static String checkNotEmpty(String param, String name) { 42 | if (param == null || param.isEmpty()) 43 | throw new IllegalArgumentException(name + " is empty"); 44 | 45 | return param; 46 | } 47 | 48 | 49 | public static long midnightMillis() { 50 | // today 51 | Calendar date = Calendar.getInstance(); 52 | // reset hour, minutes, seconds and millis 53 | date.set(Calendar.HOUR_OF_DAY, 0); 54 | date.set(Calendar.MINUTE, 0); 55 | date.set(Calendar.SECOND, 0); 56 | date.set(Calendar.MILLISECOND, 0); 57 | 58 | return date.getTimeInMillis(); 59 | } 60 | 61 | public static void main(String[] args) { 62 | // 2013-12-25 00:00:00.000 63 | System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Timestamp(midnightMillis()))); 64 | System.out.println(encode(281474976710655L)); 65 | } 66 | 67 | public static long decode(String s, String symbols) { 68 | final int B = symbols.length(); 69 | long num = 0; 70 | for (char ch : s.toCharArray()) { 71 | num *= B; 72 | num += symbols.indexOf(ch); 73 | } 74 | return num; 75 | } 76 | 77 | public static String encode(long num) { 78 | return encode(num, defaultRange); 79 | } 80 | 81 | public static String encode(long num, String symbols) { 82 | final int B = symbols.length(); 83 | StringBuilder sb = new StringBuilder(); 84 | while (num != 0) { 85 | sb.append(symbols.charAt((int) (num % B))); 86 | num /= B; 87 | } 88 | return sb.reverse().toString(); 89 | } 90 | 91 | // all un-clearly-recognized letters are skiped. 92 | static String defaultRange = "0123456789ABCDFGHKMNPRSTWXYZ"; 93 | 94 | public static String padLeft(String str, int size, char padChar) { 95 | if (str.length() >= size) return str; 96 | 97 | StringBuilder s = new StringBuilder(); 98 | for (int i = size - str.length(); i > 0; --i) { 99 | s.append(padChar); 100 | } 101 | s.append(str); 102 | 103 | return s.toString(); 104 | } 105 | 106 | public static File createIdWorkerHome() { 107 | String userHome = System.getProperty("user.home"); 108 | File idWorkerHome = new File(userHome + File.separator + DOT_IDWORKERS); 109 | idWorkerHome.mkdirs(); 110 | if (idWorkerHome.isDirectory()) return idWorkerHome; 111 | 112 | throw new RuntimeException("failed to create .idworkers at user home"); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /book-common/src/main/resources/tencentcloud.properties: -------------------------------------------------------------------------------- 1 | tencent.cloud.secretId=AKIDDD3i7F6h26sOzLRGpBMIxPindfV9dvxk 2 | tencent.cloud.secretKey=A8sNn24siNo10mLfngQvHPH4i8KIDzXq -------------------------------------------------------------------------------- /book-mapper/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.imooc 8 | imooc-red-book-dev 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | book-mapper 14 | 15 | 16 | 8 17 | 8 18 | UTF-8 19 | 20 | 21 | 22 | 23 | com.imooc 24 | book-model 25 | 1.0-SNAPSHOT 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /book-mapper/src/main/java/com/imooc/mapper/CommentMapper.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import com.imooc.my.mapper.MyMapper; 4 | import com.imooc.pojo.Comment; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface CommentMapper extends MyMapper { 9 | } -------------------------------------------------------------------------------- /book-mapper/src/main/java/com/imooc/mapper/CommentMapperCustom.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import com.imooc.vo.CommentVO; 4 | import org.apache.ibatis.annotations.Param; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | @Repository 11 | public interface CommentMapperCustom { 12 | 13 | public List getCommentList(@Param("paramMap") Map map); 14 | 15 | } -------------------------------------------------------------------------------- /book-mapper/src/main/java/com/imooc/mapper/FansMapper.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import com.imooc.my.mapper.MyMapper; 4 | import com.imooc.pojo.Fans; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface FansMapper extends MyMapper { 9 | } -------------------------------------------------------------------------------- /book-mapper/src/main/java/com/imooc/mapper/FansMapperCustom.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import com.imooc.my.mapper.MyMapper; 4 | import com.imooc.pojo.Fans; 5 | import com.imooc.vo.FansVO; 6 | import com.imooc.vo.VlogerVO; 7 | import org.apache.ibatis.annotations.Param; 8 | import org.springframework.stereotype.Repository; 9 | 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | @Repository 14 | public interface FansMapperCustom extends MyMapper { 15 | 16 | public List queryMyFollows(@Param("paramMap") Map map); 17 | 18 | public List queryMyFans(@Param("paramMap") Map map); 19 | 20 | } -------------------------------------------------------------------------------- /book-mapper/src/main/java/com/imooc/mapper/MyLikedVlogMapper.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import com.imooc.my.mapper.MyMapper; 4 | import com.imooc.pojo.MyLikedVlog; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface MyLikedVlogMapper extends MyMapper { 9 | } -------------------------------------------------------------------------------- /book-mapper/src/main/java/com/imooc/mapper/UsersMapper.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import com.imooc.my.mapper.MyMapper; 4 | import com.imooc.pojo.Users; 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | @Mapper 8 | public interface UsersMapper extends MyMapper { 9 | } -------------------------------------------------------------------------------- /book-mapper/src/main/java/com/imooc/mapper/VlogMapper.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import com.imooc.my.mapper.MyMapper; 4 | import com.imooc.pojo.Vlog; 5 | import org.springframework.stereotype.Repository; 6 | 7 | 8 | @Repository 9 | public interface VlogMapper extends MyMapper { 10 | } -------------------------------------------------------------------------------- /book-mapper/src/main/java/com/imooc/mapper/VlogMapperCustom.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import com.imooc.vo.IndexVlogVO; 4 | import org.apache.ibatis.annotations.Param; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | @Repository 11 | public interface VlogMapperCustom { 12 | 13 | public List getIndexVlogList(@Param("paramMap")Map map); 14 | 15 | public List getVlogDetailById(@Param("paramMap")Map map); 16 | 17 | public List getMyLikedVlogList(@Param("paramMap")Map map); 18 | 19 | public List getMyFollowVlogList(@Param("paramMap")Map map); 20 | 21 | public List getMyFriendVlogList(@Param("paramMap")Map map); 22 | 23 | } -------------------------------------------------------------------------------- /book-mapper/src/main/java/com/imooc/my/mapper/MyMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014-2016 abel533@gmail.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.imooc.my.mapper; 26 | 27 | import tk.mybatis.mapper.common.Mapper; 28 | import tk.mybatis.mapper.common.MySqlMapper; 29 | 30 | /** 31 | * 继承自己的MyMapper 32 | */ 33 | public interface MyMapper extends Mapper, MySqlMapper { 34 | } 35 | -------------------------------------------------------------------------------- /book-mapper/src/main/java/com/imooc/repository/MessageRepository.java: -------------------------------------------------------------------------------- 1 | package com.imooc.repository; 2 | 3 | import com.imooc.mo.MessageMO; 4 | import org.springframework.data.domain.Pageable; 5 | import org.springframework.data.mongodb.repository.MongoRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | @Repository 11 | public interface MessageRepository extends MongoRepository { 12 | 13 | // 通过实现Repository,自定义条件查询 14 | List findAllByToUserIdEqualsOrderByCreateTimeDesc(String toUserId, 15 | Pageable pageable); 16 | // void deleteAllByFromUserIdAndToUserIdAndMsgType(); 17 | } 18 | -------------------------------------------------------------------------------- /book-mapper/src/main/resources/mapper/CommentMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /book-mapper/src/main/resources/mapper/CommentMapperCustom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 45 | 46 | -------------------------------------------------------------------------------- /book-mapper/src/main/resources/mapper/FansMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /book-mapper/src/main/resources/mapper/FansMapperCustom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 24 | 25 | 44 | 45 | -------------------------------------------------------------------------------- /book-mapper/src/main/resources/mapper/MyLikedVlogMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /book-mapper/src/main/resources/mapper/UsersMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /book-mapper/src/main/resources/mapper/VlogMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /book-mapper/src/main/resources/mapper/VlogMapperCustom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 34 | 35 | 36 | 59 | 60 | 92 | 93 | 125 | 126 | 160 | 161 | -------------------------------------------------------------------------------- /book-model/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.imooc 8 | imooc-red-book-dev 9 | 1.0-SNAPSHOT 10 | 11 | 12 | book-model 13 | 14 | 15 | 8 16 | 8 17 | UTF-8 18 | 19 | 20 | 21 | 22 | com.imooc 23 | book-common 24 | 1.0-SNAPSHOT 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-validation 31 | 32 | 33 | 34 | 35 | mysql 36 | mysql-connector-java 37 | 8.0.26 38 | 39 | 40 | 41 | org.mybatis.spring.boot 42 | mybatis-spring-boot-starter 43 | 44 | 45 | 46 | tk.mybatis 47 | mapper-spring-boot-starter 48 | 49 | 50 | 51 | com.github.pagehelper 52 | pagehelper-spring-boot-starter 53 | 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-starter-data-mongodb 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/bo/CommentBO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.bo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | import org.hibernate.validator.constraints.Length; 8 | 9 | import javax.validation.constraints.NotBlank; 10 | 11 | @Data 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | @ToString 15 | public class CommentBO { 16 | 17 | @NotBlank(message = "留言信息不完整") 18 | private String vlogerId; 19 | 20 | @NotBlank(message = "留言信息不完整") 21 | private String fatherCommentId; 22 | 23 | @NotBlank(message = "留言信息不完整") 24 | private String vlogId; 25 | 26 | @NotBlank(message = "当前用户信息不正确,请尝试重新登录") 27 | private String commentUserId; 28 | 29 | @NotBlank(message = "评论内容不能为空") 30 | @Length(max = 50, message = "评论内容长度不能超过50") 31 | private String content; 32 | } -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/bo/RegistLoginBO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.bo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | import org.hibernate.validator.constraints.Length; 8 | 9 | import javax.validation.constraints.NotBlank; 10 | 11 | @Data 12 | @ToString 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | public class RegistLoginBO { 16 | 17 | @NotBlank(message = "手机号不能为空") 18 | @Length(min = 11, max = 11, message = "手机长度不正确") 19 | private String mobile; 20 | @NotBlank(message = "验证码不能为空") 21 | private String smsCode; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/bo/UpdatedUserBO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.bo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | 10 | @Data 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | @ToString 14 | public class UpdatedUserBO { 15 | private String id; 16 | private String nickname; 17 | private String imoocNum; 18 | private String face; 19 | private Integer sex; 20 | private Date birthday; 21 | private String country; 22 | private String province; 23 | private String city; 24 | private String district; 25 | private String description; 26 | private String bgImg; 27 | private Integer canImoocNumBeUpdated; 28 | } -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/bo/VlogBO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.bo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @ToString 12 | public class VlogBO { 13 | private String id; 14 | private String vlogerId; 15 | private String url; 16 | private String cover; 17 | private String title; 18 | private Integer width; 19 | private Integer height; 20 | private Integer likeCounts; 21 | private Integer commentsCounts; 22 | } -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/mo/MessageMO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | import org.springframework.data.annotation.Id; 8 | import org.springframework.data.mongodb.core.mapping.Document; 9 | import org.springframework.data.mongodb.core.mapping.Field; 10 | 11 | import java.util.Date; 12 | import java.util.Map; 13 | 14 | @Data 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | @ToString 18 | @Document("message") 19 | public class MessageMO { 20 | 21 | @Id 22 | private String id; // 消息主键id 23 | 24 | @Field("fromUserId") 25 | private String fromUserId; // 消息来自的用户id 26 | @Field("fromNickname") 27 | private String fromNickname; // 消息来自的用户昵称 28 | @Field("fromFace") 29 | private String fromFace; // 消息来自的用户头像 30 | 31 | @Field("toUserId") 32 | private String toUserId; // 消息发送到某对象的用户id 33 | 34 | @Field("msgType") 35 | private Integer msgType; // 消息类型 枚举 36 | @Field("msgContent") 37 | private Map msgContent; // 消息内容 38 | 39 | @Field("createTime") 40 | private Date createTime; // 消息创建时间 41 | } 42 | -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/pojo/Comment.java: -------------------------------------------------------------------------------- 1 | package com.imooc.pojo; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Id; 5 | import java.util.Date; 6 | 7 | public class Comment { 8 | @Id 9 | private String id; 10 | 11 | /** 12 | * 评论的视频是哪个作者(vloger)的关联id 13 | */ 14 | @Column(name = "vloger_id") 15 | private String vlogerId; 16 | 17 | /** 18 | * 如果是回复留言,则本条为子留言,需要关联查询 19 | */ 20 | @Column(name = "father_comment_id") 21 | private String fatherCommentId; 22 | 23 | /** 24 | * 回复的那个视频id 25 | */ 26 | @Column(name = "vlog_id") 27 | private String vlogId; 28 | 29 | /** 30 | * 发布留言的用户id 31 | */ 32 | @Column(name = "comment_user_id") 33 | private String commentUserId; 34 | 35 | /** 36 | * 留言内容 37 | */ 38 | private String content; 39 | 40 | /** 41 | * 留言的点赞总数 42 | */ 43 | @Column(name = "like_counts") 44 | private Integer likeCounts; 45 | 46 | /** 47 | * 留言时间 48 | */ 49 | @Column(name = "create_time") 50 | private Date createTime; 51 | 52 | /** 53 | * @return id 54 | */ 55 | public String getId() { 56 | return id; 57 | } 58 | 59 | /** 60 | * @param id 61 | */ 62 | public void setId(String id) { 63 | this.id = id; 64 | } 65 | 66 | /** 67 | * 获取评论的视频是哪个作者(vloger)的关联id 68 | * 69 | * @return vloger_id - 评论的视频是哪个作者(vloger)的关联id 70 | */ 71 | public String getVlogerId() { 72 | return vlogerId; 73 | } 74 | 75 | /** 76 | * 设置评论的视频是哪个作者(vloger)的关联id 77 | * 78 | * @param vlogerId 评论的视频是哪个作者(vloger)的关联id 79 | */ 80 | public void setVlogerId(String vlogerId) { 81 | this.vlogerId = vlogerId; 82 | } 83 | 84 | /** 85 | * 获取如果是回复留言,则本条为子留言,需要关联查询 86 | * 87 | * @return father_comment_id - 如果是回复留言,则本条为子留言,需要关联查询 88 | */ 89 | public String getFatherCommentId() { 90 | return fatherCommentId; 91 | } 92 | 93 | /** 94 | * 设置如果是回复留言,则本条为子留言,需要关联查询 95 | * 96 | * @param fatherCommentId 如果是回复留言,则本条为子留言,需要关联查询 97 | */ 98 | public void setFatherCommentId(String fatherCommentId) { 99 | this.fatherCommentId = fatherCommentId; 100 | } 101 | 102 | /** 103 | * 获取回复的那个视频id 104 | * 105 | * @return vlog_id - 回复的那个视频id 106 | */ 107 | public String getVlogId() { 108 | return vlogId; 109 | } 110 | 111 | /** 112 | * 设置回复的那个视频id 113 | * 114 | * @param vlogId 回复的那个视频id 115 | */ 116 | public void setVlogId(String vlogId) { 117 | this.vlogId = vlogId; 118 | } 119 | 120 | /** 121 | * 获取发布留言的用户id 122 | * 123 | * @return comment_user_id - 发布留言的用户id 124 | */ 125 | public String getCommentUserId() { 126 | return commentUserId; 127 | } 128 | 129 | /** 130 | * 设置发布留言的用户id 131 | * 132 | * @param commentUserId 发布留言的用户id 133 | */ 134 | public void setCommentUserId(String commentUserId) { 135 | this.commentUserId = commentUserId; 136 | } 137 | 138 | /** 139 | * 获取留言内容 140 | * 141 | * @return content - 留言内容 142 | */ 143 | public String getContent() { 144 | return content; 145 | } 146 | 147 | /** 148 | * 设置留言内容 149 | * 150 | * @param content 留言内容 151 | */ 152 | public void setContent(String content) { 153 | this.content = content; 154 | } 155 | 156 | /** 157 | * 获取留言的点赞总数 158 | * 159 | * @return like_counts - 留言的点赞总数 160 | */ 161 | public Integer getLikeCounts() { 162 | return likeCounts; 163 | } 164 | 165 | /** 166 | * 设置留言的点赞总数 167 | * 168 | * @param likeCounts 留言的点赞总数 169 | */ 170 | public void setLikeCounts(Integer likeCounts) { 171 | this.likeCounts = likeCounts; 172 | } 173 | 174 | /** 175 | * 获取留言时间 176 | * 177 | * @return create_time - 留言时间 178 | */ 179 | public Date getCreateTime() { 180 | return createTime; 181 | } 182 | 183 | /** 184 | * 设置留言时间 185 | * 186 | * @param createTime 留言时间 187 | */ 188 | public void setCreateTime(Date createTime) { 189 | this.createTime = createTime; 190 | } 191 | } -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/pojo/Fans.java: -------------------------------------------------------------------------------- 1 | package com.imooc.pojo; 2 | 3 | import org.springframework.data.annotation.Id; 4 | 5 | import javax.persistence.Column; 6 | 7 | public class Fans { 8 | @Id 9 | private String id; 10 | 11 | /** 12 | * 作家用户id 13 | */ 14 | @Column(name = "vloger_id") 15 | private String vlogerId; 16 | 17 | /** 18 | * 粉丝用户id 19 | */ 20 | @Column(name = "fan_id") 21 | private String fanId; 22 | 23 | /** 24 | * 粉丝是否是vloger的朋友,如果成为朋友,则本表的双方此字段都需要设置为1,如果有一人取关,则两边都需要设置为0 25 | */ 26 | @Column(name = "is_fan_friend_of_mine") 27 | private Integer isFanFriendOfMine; 28 | 29 | /** 30 | * @return id 31 | */ 32 | public String getId() { 33 | return id; 34 | } 35 | 36 | /** 37 | * @param id 38 | */ 39 | public void setId(String id) { 40 | this.id = id; 41 | } 42 | 43 | /** 44 | * 获取作家用户id 45 | * 46 | * @return vloger_id - 作家用户id 47 | */ 48 | public String getVlogerId() { 49 | return vlogerId; 50 | } 51 | 52 | /** 53 | * 设置作家用户id 54 | * 55 | * @param vlogerId 作家用户id 56 | */ 57 | public void setVlogerId(String vlogerId) { 58 | this.vlogerId = vlogerId; 59 | } 60 | 61 | /** 62 | * 获取粉丝用户id 63 | * 64 | * @return fan_id - 粉丝用户id 65 | */ 66 | public String getFanId() { 67 | return fanId; 68 | } 69 | 70 | /** 71 | * 设置粉丝用户id 72 | * 73 | * @param fanId 粉丝用户id 74 | */ 75 | public void setFanId(String fanId) { 76 | this.fanId = fanId; 77 | } 78 | 79 | /** 80 | * 获取粉丝是否是vloger的朋友,如果成为朋友,则本表的双方此字段都需要设置为1,如果有一人取关,则两边都需要设置为0 81 | * 82 | * @return is_fan_friend_of_mine - 粉丝是否是vloger的朋友,如果成为朋友,则本表的双方此字段都需要设置为1,如果有一人取关,则两边都需要设置为0 83 | */ 84 | public Integer getIsFanFriendOfMine() { 85 | return isFanFriendOfMine; 86 | } 87 | 88 | /** 89 | * 设置粉丝是否是vloger的朋友,如果成为朋友,则本表的双方此字段都需要设置为1,如果有一人取关,则两边都需要设置为0 90 | * 91 | * @param isFanFriendOfMine 粉丝是否是vloger的朋友,如果成为朋友,则本表的双方此字段都需要设置为1,如果有一人取关,则两边都需要设置为0 92 | */ 93 | public void setIsFanFriendOfMine(Integer isFanFriendOfMine) { 94 | this.isFanFriendOfMine = isFanFriendOfMine; 95 | } 96 | } -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/pojo/MyLikedVlog.java: -------------------------------------------------------------------------------- 1 | package com.imooc.pojo; 2 | 3 | import org.springframework.data.annotation.Id; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Table; 7 | 8 | @Table(name = "my_liked_vlog") 9 | public class MyLikedVlog { 10 | @Id 11 | private String id; 12 | 13 | /** 14 | * 用户id 15 | */ 16 | @Column(name = "user_id") 17 | private String userId; 18 | 19 | /** 20 | * 喜欢的短视频id 21 | */ 22 | @Column(name = "vlog_id") 23 | private String vlogId; 24 | 25 | /** 26 | * @return id 27 | */ 28 | public String getId() { 29 | return id; 30 | } 31 | 32 | /** 33 | * @param id 34 | */ 35 | public void setId(String id) { 36 | this.id = id; 37 | } 38 | 39 | /** 40 | * 获取用户id 41 | * 42 | * @return user_id - 用户id 43 | */ 44 | public String getUserId() { 45 | return userId; 46 | } 47 | 48 | /** 49 | * 设置用户id 50 | * 51 | * @param userId 用户id 52 | */ 53 | public void setUserId(String userId) { 54 | this.userId = userId; 55 | } 56 | 57 | /** 58 | * 获取喜欢的短视频id 59 | * 60 | * @return vlog_id - 喜欢的短视频id 61 | */ 62 | public String getVlogId() { 63 | return vlogId; 64 | } 65 | 66 | /** 67 | * 设置喜欢的短视频id 68 | * 69 | * @param vlogId 喜欢的短视频id 70 | */ 71 | public void setVlogId(String vlogId) { 72 | this.vlogId = vlogId; 73 | } 74 | } -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/pojo/Vlog.java: -------------------------------------------------------------------------------- 1 | package com.imooc.pojo; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Id; 5 | import java.util.Date; 6 | 7 | public class Vlog { 8 | @Id 9 | private String id; 10 | 11 | /** 12 | * 对应用户表id,vlog视频发布者 13 | */ 14 | @Column(name = "vloger_id") 15 | private String vlogerId; 16 | 17 | /** 18 | * 视频播放地址 19 | */ 20 | private String url; 21 | 22 | /** 23 | * 视频封面 24 | */ 25 | private String cover; 26 | 27 | /** 28 | * 视频标题,可以为空 29 | */ 30 | private String title; 31 | 32 | /** 33 | * 视频width 34 | */ 35 | private Integer width; 36 | 37 | /** 38 | * 视频height 39 | */ 40 | private Integer height; 41 | 42 | /** 43 | * 点赞总数 44 | */ 45 | @Column(name = "like_counts") 46 | private Integer likeCounts; 47 | 48 | /** 49 | * 评论总数 50 | */ 51 | @Column(name = "comments_counts") 52 | private Integer commentsCounts; 53 | 54 | /** 55 | * 是否私密,用户可以设置私密,如此可以不公开给比人看 56 | */ 57 | @Column(name = "is_private") 58 | private Integer isPrivate; 59 | 60 | /** 61 | * 创建时间 创建时间 62 | */ 63 | @Column(name = "created_time") 64 | private Date createdTime; 65 | 66 | /** 67 | * 更新时间 更新时间 68 | */ 69 | @Column(name = "updated_time") 70 | private Date updatedTime; 71 | 72 | /** 73 | * @return id 74 | */ 75 | public String getId() { 76 | return id; 77 | } 78 | 79 | /** 80 | * @param id 81 | */ 82 | public void setId(String id) { 83 | this.id = id; 84 | } 85 | 86 | /** 87 | * 获取对应用户表id,vlog视频发布者 88 | * 89 | * @return vloger_id - 对应用户表id,vlog视频发布者 90 | */ 91 | public String getVlogerId() { 92 | return vlogerId; 93 | } 94 | 95 | /** 96 | * 设置对应用户表id,vlog视频发布者 97 | * 98 | * @param vlogerId 对应用户表id,vlog视频发布者 99 | */ 100 | public void setVlogerId(String vlogerId) { 101 | this.vlogerId = vlogerId; 102 | } 103 | 104 | /** 105 | * 获取视频播放地址 106 | * 107 | * @return url - 视频播放地址 108 | */ 109 | public String getUrl() { 110 | return url; 111 | } 112 | 113 | /** 114 | * 设置视频播放地址 115 | * 116 | * @param url 视频播放地址 117 | */ 118 | public void setUrl(String url) { 119 | this.url = url; 120 | } 121 | 122 | /** 123 | * 获取视频封面 124 | * 125 | * @return cover - 视频封面 126 | */ 127 | public String getCover() { 128 | return cover; 129 | } 130 | 131 | /** 132 | * 设置视频封面 133 | * 134 | * @param cover 视频封面 135 | */ 136 | public void setCover(String cover) { 137 | this.cover = cover; 138 | } 139 | 140 | /** 141 | * 获取视频标题,可以为空 142 | * 143 | * @return title - 视频标题,可以为空 144 | */ 145 | public String getTitle() { 146 | return title; 147 | } 148 | 149 | /** 150 | * 设置视频标题,可以为空 151 | * 152 | * @param title 视频标题,可以为空 153 | */ 154 | public void setTitle(String title) { 155 | this.title = title; 156 | } 157 | 158 | /** 159 | * 获取视频width 160 | * 161 | * @return width - 视频width 162 | */ 163 | public Integer getWidth() { 164 | return width; 165 | } 166 | 167 | /** 168 | * 设置视频width 169 | * 170 | * @param width 视频width 171 | */ 172 | public void setWidth(Integer width) { 173 | this.width = width; 174 | } 175 | 176 | /** 177 | * 获取视频height 178 | * 179 | * @return height - 视频height 180 | */ 181 | public Integer getHeight() { 182 | return height; 183 | } 184 | 185 | /** 186 | * 设置视频height 187 | * 188 | * @param height 视频height 189 | */ 190 | public void setHeight(Integer height) { 191 | this.height = height; 192 | } 193 | 194 | /** 195 | * 获取点赞总数 196 | * 197 | * @return like_counts - 点赞总数 198 | */ 199 | public Integer getLikeCounts() { 200 | return likeCounts; 201 | } 202 | 203 | /** 204 | * 设置点赞总数 205 | * 206 | * @param likeCounts 点赞总数 207 | */ 208 | public void setLikeCounts(Integer likeCounts) { 209 | this.likeCounts = likeCounts; 210 | } 211 | 212 | /** 213 | * 获取评论总数 214 | * 215 | * @return comments_counts - 评论总数 216 | */ 217 | public Integer getCommentsCounts() { 218 | return commentsCounts; 219 | } 220 | 221 | /** 222 | * 设置评论总数 223 | * 224 | * @param commentsCounts 评论总数 225 | */ 226 | public void setCommentsCounts(Integer commentsCounts) { 227 | this.commentsCounts = commentsCounts; 228 | } 229 | 230 | /** 231 | * 获取是否私密,用户可以设置私密,如此可以不公开给比人看 232 | * 233 | * @return is_private - 是否私密,用户可以设置私密,如此可以不公开给比人看 234 | */ 235 | public Integer getIsPrivate() { 236 | return isPrivate; 237 | } 238 | 239 | /** 240 | * 设置是否私密,用户可以设置私密,如此可以不公开给比人看 241 | * 242 | * @param isPrivate 是否私密,用户可以设置私密,如此可以不公开给比人看 243 | */ 244 | public void setIsPrivate(Integer isPrivate) { 245 | this.isPrivate = isPrivate; 246 | } 247 | 248 | /** 249 | * 获取创建时间 创建时间 250 | * 251 | * @return created_time - 创建时间 创建时间 252 | */ 253 | public Date getCreatedTime() { 254 | return createdTime; 255 | } 256 | 257 | /** 258 | * 设置创建时间 创建时间 259 | * 260 | * @param createdTime 创建时间 创建时间 261 | */ 262 | public void setCreatedTime(Date createdTime) { 263 | this.createdTime = createdTime; 264 | } 265 | 266 | /** 267 | * 获取更新时间 更新时间 268 | * 269 | * @return updated_time - 更新时间 更新时间 270 | */ 271 | public Date getUpdatedTime() { 272 | return updatedTime; 273 | } 274 | 275 | /** 276 | * 设置更新时间 更新时间 277 | * 278 | * @param updatedTime 更新时间 更新时间 279 | */ 280 | public void setUpdatedTime(Date updatedTime) { 281 | this.updatedTime = updatedTime; 282 | } 283 | } -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/vo/CommentVO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | 10 | @Data 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | @ToString 14 | public class CommentVO { 15 | private String id; 16 | private String commentId; 17 | private String vlogerId; 18 | private String fatherCommentId; 19 | private String vlogId; 20 | private String commentUserId; 21 | private String commentUserNickname; 22 | private String commentUserFace; 23 | private String content; 24 | private Integer likeCounts; 25 | private String replyedUserNickname; 26 | private Date createTime; 27 | private Integer isLike = 0; 28 | } -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/vo/FansVO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @ToString 12 | public class FansVO { 13 | private String fanId; 14 | private String nickname; 15 | private String face; 16 | private boolean isFriend = false; 17 | } -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/vo/IndexVlogVO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @ToString 12 | public class IndexVlogVO { 13 | private String vlogId; 14 | private String vlogerId; 15 | private String vlogerFace; 16 | private String vlogerName; 17 | private String content; 18 | private String url; 19 | private String cover; 20 | private Integer width; 21 | private Integer height; 22 | private Integer likeCounts; 23 | private Integer commentsCounts; 24 | private Integer isPrivate; 25 | private boolean isPlay = false; 26 | private boolean doIFollowVloger = false; 27 | private boolean doILikeThisVlog = false; 28 | } -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/vo/UsersVO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | import javax.persistence.Column; 9 | import javax.persistence.Id; 10 | import javax.validation.constraints.NotBlank; 11 | import java.util.Date; 12 | 13 | @Data 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | @ToString 17 | public class UsersVO { 18 | private String id; 19 | private String mobile; 20 | private String nickname; 21 | private String imoocNum; 22 | private String face; 23 | private Integer sex; 24 | private Date birthday; 25 | private String country; 26 | private String province; 27 | private String city; 28 | private String district; 29 | private String description; 30 | private String bgImg; 31 | private Integer canImoocNumBeUpdated; 32 | private Date createdTime; 33 | private Date updatedTime; 34 | 35 | private String userToken; // 用户token,传递给前端 36 | 37 | private Integer myFollowsCounts; //我关注的 38 | private Integer myFansCounts; //我的粉丝数量 39 | //private Integer myLikedVlogCounts; 40 | private Integer totalLikeMeCounts; 41 | 42 | } -------------------------------------------------------------------------------- /book-model/src/main/java/com/imooc/vo/VlogerVO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @ToString 12 | public class VlogerVO { 13 | private String vlogerId; 14 | private String nickname; 15 | private String face; 16 | private boolean isFollowed = true; 17 | } -------------------------------------------------------------------------------- /book-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.imooc 8 | imooc-red-book-dev 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | book-service 14 | 15 | 16 | 8 17 | 8 18 | UTF-8 19 | 20 | 21 | 22 | 23 | com.imooc 24 | book-mapper 25 | 1.0-SNAPSHOT 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /book-service/src/main/java/com/imooc/base/BaseInfoProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.base; 2 | 3 | import com.github.pagehelper.PageInfo; 4 | //import com.imooc.utils.PagedGridResult; 5 | import com.imooc.utils.PagedGridResult; 6 | import com.imooc.utils.RedisOperator; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | 9 | import java.util.List; 10 | 11 | public class BaseInfoProperties { 12 | 13 | @Autowired 14 | public RedisOperator redis; 15 | 16 | public static final Integer COMMON_START_PAGE = 1; 17 | public static final Integer COMMON_START_PAGE_ZERO = 0; 18 | public static final Integer COMMON_PAGE_SIZE = 10; 19 | 20 | public static final String MOBILE_SMSCODE = "mobile:smscode"; 21 | public static final String REDIS_USER_TOKEN = "redis_user_token"; 22 | public static final String REDIS_USER_INFO = "redis_user_info"; 23 | 24 | // 短视频的评论总数 25 | public static final String REDIS_VLOG_COMMENT_COUNTS = "redis_vlog_comment_counts"; 26 | // 短视频的评论喜欢数量 27 | public static final String REDIS_VLOG_COMMENT_LIKED_COUNTS = "redis_vlog_comment_liked_counts"; 28 | // 用户点赞评论 29 | public static final String REDIS_USER_LIKE_COMMENT = "redis_user_like_comment"; 30 | 31 | 32 | //我的关注总数 33 | public static final String REDIS_MY_FOLLOWS_COUNTS = "redis_my_follows_counts"; 34 | // 我的粉丝总数 35 | public static final String REDIS_MY_FANS_COUNTS = "redis_my_fans_counts"; 36 | 37 | // 视频和发布者获赞数 38 | public static final String REDIS_VLOG_BE_LIKED_COUNTS = "redis_vlog_be_liked_counts"; 39 | public static final String REDIS_VLOGER_BE_LIKED_COUNTS = "redis_vloger_be_liked_counts"; 40 | 41 | // 博主和粉丝的关联关系,用于判断他们是否互粉 42 | public static final String REDIS_FANS_AND_VLOGGER_RELATIONSHIP = "redis_fans_and_vlogger_relationship"; 43 | 44 | // 用户是否喜欢/点赞视频,取代数据库的关联关系,1:喜欢,0:不喜欢(默认) redis_user_like_vlog:{userId}:{vlogId} 45 | public static final String REDIS_USER_LIKE_VLOG = "redis_user_like_vlog"; 46 | 47 | public PagedGridResult setterPagedGrid(List list, Integer page) { 48 | PageInfo pageList = new PageInfo<>(list); 49 | PagedGridResult gridResult = new PagedGridResult(); 50 | gridResult.setRows(list); 51 | gridResult.setPage(page); 52 | gridResult.setRecords(pageList.getTotal()); 53 | gridResult.setTotal(pageList.getPages()); 54 | return gridResult; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /book-service/src/main/java/com/imooc/base/RabbitMQConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.base;//package com.imooc; 2 | 3 | import org.springframework.amqp.core.*; 4 | import org.springframework.beans.factory.annotation.Qualifier; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class RabbitMQConfig { 10 | 11 | /** 12 | * 根据模型编写代码: 13 | * 1. 定义交换机 14 | * 2. 定义队列 15 | * 3. 创建交换机 16 | * 4. 创建队列 17 | * 5. 队列和交换机的绑定 18 | */ 19 | 20 | public static final String EXCHANGE_MSG = "exchange_msg"; 21 | 22 | public static final String QUEUE_SYS_MSG = "queue_sys_msg"; 23 | 24 | @Bean(EXCHANGE_MSG) 25 | public Exchange exchange() { 26 | return ExchangeBuilder // 构建交换机 27 | .topicExchange(EXCHANGE_MSG) // 使用topic类型,参考:https://www.rabbitmq.com/getstarted.html 28 | .durable(true) // 设置持久化,重启mq后依然存在 29 | .build(); 30 | } 31 | 32 | @Bean(QUEUE_SYS_MSG) 33 | public Queue queue() { 34 | return new Queue(QUEUE_SYS_MSG); 35 | } 36 | 37 | @Bean 38 | public Binding binding(@Qualifier(EXCHANGE_MSG) Exchange exchange, 39 | @Qualifier(QUEUE_SYS_MSG) Queue queue) { 40 | 41 | return BindingBuilder 42 | .bind(queue) 43 | .to(exchange) 44 | .with("sys.msg.*") // 定义路由规则(requestMapping) 45 | .noargs(); 46 | 47 | // FIXME: * 和 # 分别代表什么意思? 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /book-service/src/main/java/com/imooc/service/CommentService.java: -------------------------------------------------------------------------------- 1 | package com.imooc.service; 2 | 3 | import com.imooc.bo.CommentBO; 4 | import com.imooc.pojo.Comment; 5 | import com.imooc.pojo.Vlog; 6 | import com.imooc.utils.PagedGridResult; 7 | import com.imooc.vo.CommentVO; 8 | 9 | public interface CommentService { 10 | 11 | /** 12 | * 发表评论 13 | */ 14 | public CommentVO createComment(CommentBO commentBO); 15 | 16 | /** 17 | * 查询评论的列表 18 | */ 19 | public PagedGridResult queryVlogComments(String vlogId, 20 | String userId, 21 | Integer page, 22 | Integer pageSize); 23 | 24 | /** 25 | * 删除评论 26 | */ 27 | public void deleteComment(String commentUserId, 28 | String commentId, 29 | String vlogId); 30 | 31 | /** 32 | * 根据主键查询comment 33 | */ 34 | public Comment getComment(String id); 35 | } 36 | -------------------------------------------------------------------------------- /book-service/src/main/java/com/imooc/service/FansService.java: -------------------------------------------------------------------------------- 1 | package com.imooc.service; 2 | 3 | import com.imooc.utils.PagedGridResult; 4 | 5 | public interface FansService { 6 | 7 | /** 8 | * 关注 9 | */ 10 | public void doFollow(String myId, String vlogerId); 11 | 12 | /** 13 | * 取关 14 | */ 15 | public void doCancel(String myId, String vlogerId); 16 | 17 | /** 18 | * 查询用户是否关注博主 19 | */ 20 | public boolean queryDoIFollowVloger(String myId, String vlogerId); 21 | 22 | /** 23 | * 查询我关注的博主列表 24 | */ 25 | public PagedGridResult queryMyFollows(String myId, 26 | Integer page, 27 | Integer pageSize); 28 | 29 | /** 30 | * 查询我的粉丝列表 31 | */ 32 | public PagedGridResult queryMyFans(String myId, 33 | Integer page, 34 | Integer pageSize); 35 | } 36 | -------------------------------------------------------------------------------- /book-service/src/main/java/com/imooc/service/MsgService.java: -------------------------------------------------------------------------------- 1 | package com.imooc.service; 2 | 3 | import com.imooc.bo.VlogBO; 4 | import com.imooc.mo.MessageMO; 5 | 6 | import javax.validation.constraints.Max; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | public interface MsgService { 11 | 12 | /** 13 | * 创建消息 14 | */ 15 | public void createMsg(String fromUserId, 16 | String toUserId, 17 | Integer type, 18 | Map msgContent); 19 | 20 | /** 21 | * 查询消息列表 22 | */ 23 | public List queryList(String toUserId, 24 | Integer page, 25 | Integer pageSize); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /book-service/src/main/java/com/imooc/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.imooc.service; 2 | 3 | import com.imooc.bo.UpdatedUserBO; 4 | import com.imooc.pojo.Users; 5 | 6 | /** 7 | * @author vercen 8 | * @version 1.0 9 | * @date 2023/5/25 21:02 10 | */ 11 | public interface UserService { 12 | /** 13 | * 判断用户是否存在,如果存在则返回用户信息 14 | */ 15 | public Users queryMobileIsExist(String mobile); 16 | 17 | 18 | /** 19 | * 创建用户信息,并且返回用户对象 20 | */ 21 | public Users createUser(String mobile); 22 | 23 | /** 24 | * 根据用户主键查询用户信息 25 | */ 26 | public Users getUser(String userId); 27 | 28 | /** 29 | * 用户信息修改 30 | */ 31 | public Users updateUserInfo(UpdatedUserBO updatedUserBO); 32 | 33 | /** 34 | * 用户信息修改 35 | */ 36 | public Users updateUserInfo(UpdatedUserBO updatedUserBO, Integer type); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /book-service/src/main/java/com/imooc/service/VlogService.java: -------------------------------------------------------------------------------- 1 | package com.imooc.service; 2 | 3 | import com.imooc.bo.VlogBO; 4 | import com.imooc.pojo.Vlog; 5 | import com.imooc.utils.PagedGridResult; 6 | import com.imooc.vo.IndexVlogVO; 7 | 8 | public interface VlogService { 9 | 10 | /** 11 | * 新增vlog视频 12 | */ 13 | public void createVlog(VlogBO vlogBO); 14 | 15 | /** 16 | * 查询首页/搜索的vlog列表 17 | */ 18 | public PagedGridResult getIndexVlogList(String userId, 19 | String search, 20 | Integer page, 21 | Integer pageSize); 22 | 23 | /** 24 | * 根据视频主键查询vlog 25 | */ 26 | public IndexVlogVO getVlogDetailById(String userId, String vlogId); 27 | 28 | /** 29 | * 用户把视频改为公开/私密的视频 30 | */ 31 | public void changeToPrivateOrPublic(String userId, 32 | String vlogId, 33 | Integer yesOrNo); 34 | 35 | /** 36 | * 查询用的公开/私密的视频列表 37 | */ 38 | public PagedGridResult queryMyVlogList(String userId, 39 | Integer page, 40 | Integer pageSize, 41 | Integer yesOrNo); 42 | 43 | /** 44 | * 用户点赞/喜欢视频 45 | */ 46 | public void userLikeVlog(String userId, String vlogId); 47 | 48 | /** 49 | * 用户取消点赞/喜欢视频 50 | */ 51 | public void userUnLikeVlog(String userId, String vlogId); 52 | 53 | /** 54 | * 获得用户点赞视频的总数 55 | */ 56 | public Integer getVlogBeLikedCounts(String vlogId); 57 | 58 | /** 59 | * 查询用户点赞过的短视频 60 | */ 61 | public PagedGridResult getMyLikedVlogList(String userId, 62 | Integer page, 63 | Integer pageSize); 64 | 65 | /** 66 | * 查询用户关注的博主发布的短视频列表 67 | */ 68 | public PagedGridResult getMyFollowVlogList(String myId, 69 | Integer page, 70 | Integer pageSize); 71 | 72 | /** 73 | * 查询朋友发布的短视频列表 74 | */ 75 | public PagedGridResult getMyFriendVlogList(String myId, 76 | Integer page, 77 | Integer pageSize); 78 | 79 | /** 80 | * 根据主键查询vlog 81 | */ 82 | public Vlog getVlog(String id); 83 | 84 | /** 85 | * 把counts输入数据库 86 | */ 87 | public void flushCounts(String vlogId, Integer counts); 88 | // /** 89 | // * 查询首页/搜索的vlog列表 90 | // */ 91 | // public PagedGridResult getIndexVlogList(String userId, 92 | // String search, 93 | // Integer page, 94 | // Integer pageSize); 95 | // 96 | // /** 97 | // * 根据视频主键查询vlog 98 | // */ 99 | // public IndexVlogVO getVlogDetailById(String userId, String vlogId); 100 | // 101 | // /** 102 | // * 用户把视频改为公开/私密的视频 103 | // */ 104 | // public void changeToPrivateOrPublic(String userId, 105 | // String vlogId, 106 | // Integer yesOrNo); 107 | // 108 | // /** 109 | // * 查询用的公开/私密的视频列表 110 | // */ 111 | // public PagedGridResult queryMyVlogList(String userId, 112 | // Integer page, 113 | // Integer pageSize, 114 | // Integer yesOrNo); 115 | // 116 | // /** 117 | // * 用户点赞/喜欢视频 118 | // */ 119 | // public void userLikeVlog(String userId, String vlogId); 120 | // 121 | // /** 122 | // * 用户取消点赞/喜欢视频 123 | // */ 124 | // public void userUnLikeVlog(String userId, String vlogId); 125 | // 126 | // /** 127 | // * 获得用户点赞视频的总数 128 | // */ 129 | // public Integer getVlogBeLikedCounts(String vlogId); 130 | // 131 | // /** 132 | // * 查询用户点赞过的短视频 133 | // */ 134 | // public PagedGridResult getMyLikedVlogList(String userId, 135 | // Integer page, 136 | // Integer pageSize); 137 | // 138 | // /** 139 | // * 查询用户关注的博主发布的短视频列表 140 | // */ 141 | // public PagedGridResult getMyFollowVlogList(String myId, 142 | // Integer page, 143 | // Integer pageSize); 144 | // 145 | // /** 146 | // * 查询朋友发布的短视频列表 147 | // */ 148 | // public PagedGridResult getMyFriendVlogList(String myId, 149 | // Integer page, 150 | // Integer pageSize); 151 | // 152 | // /** 153 | // * 根据主键查询vlog 154 | // */ 155 | // public Vlog getVlog(String id); 156 | } 157 | -------------------------------------------------------------------------------- /book-service/src/main/java/com/imooc/service/impl/CommentServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.imooc.service.impl; 2 | 3 | import com.github.pagehelper.PageHelper; 4 | import com.imooc.base.BaseInfoProperties; 5 | import com.imooc.bo.CommentBO; 6 | import com.imooc.enums.MessageEnum; 7 | import com.imooc.enums.YesOrNo; 8 | import com.imooc.mapper.CommentMapper; 9 | import com.imooc.mapper.CommentMapperCustom; 10 | import com.imooc.pojo.Comment; 11 | import com.imooc.pojo.Vlog; 12 | import com.imooc.service.CommentService; 13 | import com.imooc.service.MsgService; 14 | import com.imooc.service.VlogService; 15 | import com.imooc.utils.PagedGridResult; 16 | import com.imooc.vo.CommentVO; 17 | import org.apache.commons.lang3.StringUtils; 18 | import org.n3r.idworker.Sid; 19 | import org.springframework.beans.BeanUtils; 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.stereotype.Service; 22 | 23 | import java.util.Date; 24 | import java.util.HashMap; 25 | import java.util.List; 26 | import java.util.Map; 27 | 28 | @Service 29 | public class CommentServiceImpl extends BaseInfoProperties implements CommentService { 30 | // 31 | @Autowired 32 | private CommentMapper commentMapper; 33 | // 34 | @Autowired 35 | private CommentMapperCustom commentMapperCustom; 36 | // 37 | @Autowired 38 | private VlogService vlogService; 39 | @Autowired 40 | private MsgService msgService; 41 | // 42 | @Autowired 43 | private Sid sid; 44 | // 45 | @Override 46 | public CommentVO createComment(CommentBO commentBO) { 47 | 48 | String commentId = sid.nextShort(); 49 | 50 | Comment comment = new Comment(); 51 | comment.setId(commentId); 52 | 53 | comment.setVlogId(commentBO.getVlogId()); 54 | comment.setVlogerId(commentBO.getVlogerId()); 55 | 56 | comment.setCommentUserId(commentBO.getCommentUserId()); 57 | comment.setFatherCommentId(commentBO.getFatherCommentId()); 58 | comment.setContent(commentBO.getContent()); 59 | 60 | comment.setLikeCounts(0); 61 | comment.setCreateTime(new Date()); 62 | 63 | commentMapper.insert(comment); 64 | 65 | // redis操作放在service中,评论总数的累加 66 | redis.increment(REDIS_VLOG_COMMENT_COUNTS + ":" + commentBO.getVlogId(), 1); 67 | 68 | // 留言后的最新评论需要返回给前端进行展示 69 | CommentVO commentVO = new CommentVO(); 70 | BeanUtils.copyProperties(comment, commentVO); 71 | 72 | 73 | 74 | // 系统消息:评论/回复 75 | Vlog vlog = vlogService.getVlog(commentBO.getVlogId()); 76 | Map msgContent = new HashMap(); 77 | msgContent.put("vlogId", vlog.getId()); 78 | msgContent.put("vlogCover", vlog.getCover()); 79 | msgContent.put("commentId", commentId); 80 | msgContent.put("commentContent", commentBO.getContent()); 81 | Integer type = MessageEnum.COMMENT_VLOG.type; 82 | if (StringUtils.isNotBlank(commentBO.getFatherCommentId()) && 83 | !commentBO.getFatherCommentId().equalsIgnoreCase("0") ) { 84 | type = MessageEnum.REPLY_YOU.type; 85 | } 86 | 87 | msgService.createMsg(commentBO.getCommentUserId(), 88 | commentBO.getVlogerId(), 89 | type, 90 | msgContent); 91 | // 92 | // 93 | // 94 | return commentVO; 95 | } 96 | // 97 | @Override 98 | public PagedGridResult queryVlogComments(String vlogId, 99 | String userId, 100 | Integer page, 101 | Integer pageSize) { 102 | 103 | Map map = new HashMap<>(); 104 | map.put("vlogId", vlogId); 105 | 106 | PageHelper.startPage(page, pageSize); 107 | 108 | List list = commentMapperCustom.getCommentList(map); 109 | 110 | for (CommentVO cv:list) { 111 | String commentId = cv.getCommentId(); 112 | 113 | // 当前短视频的某个评论的点赞总数 114 | String countsStr = redis.getHashValue(REDIS_VLOG_COMMENT_LIKED_COUNTS, commentId); 115 | Integer counts = 0; 116 | if (StringUtils.isNotBlank(countsStr)) { 117 | counts = Integer.valueOf(countsStr); 118 | } 119 | cv.setLikeCounts(counts); 120 | 121 | // 判断当前用户是否点赞过该评论 122 | String doILike = redis.hget(REDIS_USER_LIKE_COMMENT, userId + ":" + commentId); 123 | if (StringUtils.isNotBlank(doILike) && doILike.equalsIgnoreCase("1")) { 124 | cv.setIsLike(YesOrNo.YES.type); 125 | } 126 | } 127 | 128 | return setterPagedGrid(list, page); 129 | } 130 | 131 | @Override 132 | public void deleteComment(String commentUserId, 133 | String commentId, 134 | String vlogId) { 135 | 136 | Comment pendingDelete = new Comment(); 137 | pendingDelete.setId(commentId); 138 | pendingDelete.setCommentUserId(commentUserId); 139 | 140 | commentMapper.delete(pendingDelete); 141 | 142 | // 评论总数的累减 143 | redis.decrement(REDIS_VLOG_COMMENT_COUNTS + ":" + vlogId, 1); 144 | } 145 | 146 | @Override 147 | public Comment getComment(String id) { 148 | return commentMapper.selectByPrimaryKey(id); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /book-service/src/main/java/com/imooc/service/impl/FansServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.imooc.service.impl; 2 | 3 | import com.github.pagehelper.PageHelper; 4 | import com.imooc.base.BaseInfoProperties; 5 | import com.imooc.base.RabbitMQConfig; 6 | import com.imooc.enums.MessageEnum; 7 | import com.imooc.enums.YesOrNo; 8 | import com.imooc.mapper.FansMapper; 9 | import com.imooc.mapper.FansMapperCustom; 10 | import com.imooc.mo.MessageMO; 11 | import com.imooc.pojo.Fans; 12 | import com.imooc.service.FansService; 13 | import com.imooc.service.MsgService; 14 | import com.imooc.utils.JsonUtils; 15 | import com.imooc.utils.PagedGridResult; 16 | import com.imooc.vo.FansVO; 17 | import com.imooc.vo.VlogerVO; 18 | import org.apache.commons.lang3.StringUtils; 19 | import org.n3r.idworker.Sid; 20 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.stereotype.Service; 23 | import org.springframework.transaction.annotation.Transactional; 24 | import tk.mybatis.mapper.entity.Example; 25 | 26 | import java.util.HashMap; 27 | import java.util.List; 28 | import java.util.Map; 29 | 30 | @Service 31 | public class FansServiceImpl extends BaseInfoProperties implements FansService { 32 | 33 | @Autowired 34 | private FansMapper fansMapper; 35 | @Autowired 36 | private FansMapperCustom fansMapperCustom; 37 | // 38 | @Autowired 39 | private MsgService msgService; 40 | 41 | @Autowired 42 | public RabbitTemplate rabbitTemplate; 43 | // 44 | @Autowired 45 | private Sid sid; 46 | // 47 | @Transactional 48 | @Override 49 | public void doFollow(String myId, String vlogerId) { 50 | 51 | String fid = sid.nextShort(); 52 | 53 | Fans fans = new Fans(); 54 | fans.setId(fid); 55 | fans.setFanId(myId); 56 | fans.setVlogerId(vlogerId); 57 | 58 | // 判断对方是否关注我,如果关注我,那么双方都要互为朋友关系 59 | Fans vloger = queryFansRelationship(vlogerId, myId); 60 | if (vloger != null) { 61 | fans.setIsFanFriendOfMine(YesOrNo.YES.type); 62 | 63 | vloger.setIsFanFriendOfMine(YesOrNo.YES.type); 64 | fansMapper.updateByPrimaryKeySelective(vloger); 65 | } else { 66 | fans.setIsFanFriendOfMine(YesOrNo.NO.type); 67 | } 68 | 69 | fansMapper.insert(fans); 70 | 71 | 72 | // 系统消息:关注 73 | // msgService.createMsg(myId, vlogerId, MessageEnum.FOLLOW_YOU.type, null); 74 | //优化使用mQEXCHANGE_MSG 75 | 76 | MessageMO messageMO = new MessageMO(); 77 | 78 | messageMO.setFromUserId(myId); 79 | messageMO.setToUserId(vlogerId); 80 | rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_MSG, "sys.msg."+ MessageEnum.FOLLOW_YOU.enValue, JsonUtils.objectToJson(messageMO)); 81 | } 82 | 83 | public Fans queryFansRelationship(String fanId, String vlogerId) { 84 | Example example = new Example(Fans.class); 85 | Example.Criteria criteria = example.createCriteria(); 86 | criteria.andEqualTo("vlogerId", vlogerId); 87 | criteria.andEqualTo("fanId", fanId); 88 | 89 | List list = fansMapper.selectByExample(example); 90 | 91 | Fans fan = null; 92 | if (list != null && list.size() > 0 && !list.isEmpty()) { 93 | fan = (Fans)list.get(0); 94 | } 95 | 96 | return fan; 97 | } 98 | 99 | @Transactional 100 | @Override 101 | public void doCancel(String myId, String vlogerId) { 102 | 103 | // 判断我们是否朋友关系,如果是,则需要取消双方的关系 104 | Fans fan = queryFansRelationship(myId, vlogerId); 105 | if (fan != null && fan.getIsFanFriendOfMine() == YesOrNo.YES.type) { 106 | // 抹除双方的朋友关系,自己的关系删除即可 107 | Fans pendingFan = queryFansRelationship(vlogerId, myId); 108 | pendingFan.setIsFanFriendOfMine(YesOrNo.NO.type); 109 | fansMapper.updateByPrimaryKeySelective(pendingFan); 110 | } 111 | 112 | // 删除自己的关注关联表记录 113 | fansMapper.delete(fan); 114 | } 115 | 116 | @Override 117 | public boolean queryDoIFollowVloger(String myId, String vlogerId) { 118 | Fans vloger = queryFansRelationship(myId, vlogerId); 119 | return vloger != null; 120 | } 121 | 122 | @Override 123 | public PagedGridResult queryMyFollows(String myId, 124 | Integer page, 125 | Integer pageSize) { 126 | Map map = new HashMap<>(); 127 | map.put("myId", myId); 128 | 129 | PageHelper.startPage(page, pageSize); 130 | 131 | List list = fansMapperCustom.queryMyFollows(map); 132 | 133 | return setterPagedGrid(list, page); 134 | } 135 | 136 | @Override 137 | public PagedGridResult queryMyFans(String myId, 138 | Integer page, 139 | Integer pageSize) { 140 | 141 | /** 142 | * <判断粉丝是否是我的朋友(互粉互关)> 143 | * 普通做法: 144 | * 多表关联+嵌套关联查询,这样会违反多表关联的规范,不可取,高并发下回出现性能问题 145 | * 146 | * 常规做法: 147 | * 1. 避免过多的表关联查询,先查询我的粉丝列表,获得fansList 148 | * 2. 判断粉丝关注我,并且我也关注粉丝 -> 循环fansList,获得每一个粉丝,再去数据库查询我是否关注他 149 | * 3. 如果我也关注他(粉丝),说明,我俩互为朋友关系(互关互粉),则标记flag为true,否则false 150 | * 151 | * 高端做法: 152 | * 1. 关注/取关的时候,关联关系保存在redis中,不要依赖数据库 153 | * 2. 数据库查询后,直接循环查询redis,避免第二次循环查询数据库的尴尬局面 154 | */ 155 | 156 | 157 | Map map = new HashMap<>(); 158 | map.put("myId", myId); 159 | 160 | PageHelper.startPage(page, pageSize); 161 | 162 | List list = fansMapperCustom.queryMyFans(map); 163 | 164 | for (FansVO f : list) { 165 | String relationship = redis.get(REDIS_FANS_AND_VLOGGER_RELATIONSHIP + ":" + myId + ":" + f.getFanId()); 166 | if (StringUtils.isNotBlank(relationship) && relationship.equalsIgnoreCase("1")) { 167 | f.setFriend(true); 168 | } 169 | } 170 | 171 | return setterPagedGrid(list, page); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /book-service/src/main/java/com/imooc/service/impl/MsgServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.imooc.service.impl; 2 | 3 | import com.imooc.base.BaseInfoProperties; 4 | import com.imooc.enums.MessageEnum; 5 | import com.imooc.mo.MessageMO; 6 | import com.imooc.pojo.Users; 7 | import com.imooc.repository.MessageRepository; 8 | import com.imooc.service.MsgService; 9 | import com.imooc.service.UserService; 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.data.domain.PageRequest; 13 | import org.springframework.data.domain.Pageable; 14 | import org.springframework.data.domain.Sort; 15 | import org.springframework.stereotype.Service; 16 | 17 | import java.util.Date; 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | @Service 23 | public class MsgServiceImpl extends BaseInfoProperties implements MsgService { 24 | 25 | @Autowired 26 | private MessageRepository messageRepository; 27 | 28 | @Autowired 29 | private UserService userService; 30 | 31 | @Override 32 | public void createMsg(String fromUserId, 33 | String toUserId, 34 | Integer type, 35 | Map msgContent) { 36 | 37 | Users fromUser = userService.getUser(fromUserId); 38 | 39 | MessageMO messageMO = new MessageMO(); 40 | 41 | messageMO.setFromUserId(fromUserId); 42 | messageMO.setFromNickname(fromUser.getNickname()); 43 | messageMO.setFromFace(fromUser.getFace()); 44 | 45 | messageMO.setToUserId(toUserId); 46 | 47 | messageMO.setMsgType(type); 48 | if (msgContent != null) { 49 | messageMO.setMsgContent(msgContent); 50 | } 51 | 52 | messageMO.setCreateTime(new Date()); 53 | 54 | messageRepository.save(messageMO); 55 | } 56 | // 57 | @Override 58 | public List queryList(String toUserId, 59 | Integer page, 60 | Integer pageSize) { 61 | 62 | Pageable pageable = PageRequest.of(page, 63 | pageSize, 64 | Sort.Direction.DESC, 65 | "createTime"); 66 | 67 | List list = messageRepository 68 | .findAllByToUserIdEqualsOrderByCreateTimeDesc(toUserId, 69 | pageable); 70 | for (MessageMO msg : list) { 71 | // 如果类型是关注消息,则需要查询我之前有没有关注过他,用于在前端标记“互粉”“互关” 72 | if (msg.getMsgType() != null && msg.getMsgType() == MessageEnum.FOLLOW_YOU.type) { 73 | Map map = msg.getMsgContent(); 74 | if (map == null) { 75 | map = new HashMap(); 76 | } 77 | 78 | String relationship = redis.get(REDIS_FANS_AND_VLOGGER_RELATIONSHIP + ":" + msg.getToUserId() + ":" + msg.getFromUserId()); 79 | if (StringUtils.isNotBlank(relationship) && relationship.equalsIgnoreCase("1")) { 80 | map.put("isFriend", true); 81 | } else { 82 | map.put("isFriend", false); 83 | } 84 | msg.setMsgContent(map); 85 | } 86 | } 87 | return list; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /book-service/src/main/java/com/imooc/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.imooc.service.impl; 2 | 3 | import com.imooc.bo.UpdatedUserBO; 4 | import com.imooc.enums.Sex; 5 | import com.imooc.enums.UserInfoModifyType; 6 | import com.imooc.enums.YesOrNo; 7 | import com.imooc.exceptions.GraceException; 8 | import com.imooc.grace.result.ResponseStatusEnum; 9 | import com.imooc.mapper.UsersMapper; 10 | import com.imooc.pojo.Users; 11 | import com.imooc.service.UserService; 12 | import com.imooc.utils.DateUtil; 13 | import com.imooc.utils.DesensitizationUtil; 14 | import org.n3r.idworker.Sid; 15 | import org.springframework.beans.BeanUtils; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.stereotype.Service; 18 | import org.springframework.transaction.annotation.Transactional; 19 | import tk.mybatis.mapper.entity.Example; 20 | 21 | import java.util.Date; 22 | 23 | /** 24 | * @author vercen 25 | * @version 1.0 26 | * @date 2023/5/25 21:02 27 | */ 28 | @Service 29 | public class UserServiceImpl implements UserService { 30 | @Autowired 31 | private UsersMapper usersMapper; 32 | 33 | @Autowired 34 | private Sid sid; 35 | private static final String USER_FACE1 = "http://122.152.205.72:88/group1/M00/00/05/CpoxxF6ZUySASMbOAABBAXhjY0Y649.png"; 36 | 37 | @Override 38 | public Users queryMobileIsExist(String mobile) { 39 | Example userExample = new Example(Users.class); 40 | Example.Criteria criteria = userExample.createCriteria(); 41 | criteria.andEqualTo("mobile", mobile); 42 | Users user = usersMapper.selectOneByExample(userExample); 43 | return user; 44 | } 45 | 46 | @Override 47 | public Users createUser(String mobile) { 48 | // 获得全局唯一主键 49 | String userId = sid.nextShort(); 50 | 51 | Users user = new Users(); 52 | user.setId(userId); 53 | 54 | user.setMobile(mobile); 55 | user.setNickname("用户:" + DesensitizationUtil.commonDisplay(mobile)); 56 | user.setImoocNum("用户:" + DesensitizationUtil.commonDisplay(mobile)); 57 | user.setFace(USER_FACE1); 58 | 59 | user.setBirthday(DateUtil.stringToDate("1900-01-01")); 60 | user.setSex(Sex.secret.type); 61 | 62 | user.setCountry("中国"); 63 | user.setProvince(""); 64 | user.setCity(""); 65 | user.setDistrict(""); 66 | user.setDescription("这家伙很懒,什么都没留下~"); 67 | user.setCanImoocNumBeUpdated(YesOrNo.YES.type); 68 | 69 | user.setCreatedTime(new Date()); 70 | user.setUpdatedTime(new Date()); 71 | 72 | usersMapper.insert(user); 73 | 74 | return user; 75 | } 76 | 77 | @Override 78 | public Users getUser(String userId) { 79 | Users users = usersMapper.selectByPrimaryKey(userId); 80 | return users; 81 | } 82 | 83 | @Transactional 84 | @Override 85 | public Users updateUserInfo(UpdatedUserBO updatedUserBO) { 86 | 87 | Users users = new Users(); 88 | BeanUtils.copyProperties(updatedUserBO, users); 89 | usersMapper.updateByPrimaryKeySelective(users); 90 | return getUser(updatedUserBO.getId()); 91 | } 92 | 93 | @Transactional 94 | @Override 95 | public Users updateUserInfo(UpdatedUserBO updatedUserBO, Integer type) { 96 | 97 | Example example = new Example(Users.class); 98 | Example.Criteria criteria = example.createCriteria(); 99 | if (type == UserInfoModifyType.NICKNAME.type) { 100 | criteria.andEqualTo("nickname", updatedUserBO.getNickname()); 101 | Users user = usersMapper.selectOneByExample(example); 102 | if (user != null) { 103 | GraceException.display(ResponseStatusEnum.USER_INFO_UPDATED_NICKNAME_EXIST_ERROR); 104 | } 105 | } 106 | 107 | if (type == UserInfoModifyType.IMOOCNUM.type) { 108 | criteria.andEqualTo("imoocNum", updatedUserBO.getImoocNum()); 109 | Users user = usersMapper.selectOneByExample(example); 110 | if (user != null) { 111 | GraceException.display(ResponseStatusEnum.USER_INFO_UPDATED_NICKNAME_EXIST_ERROR); 112 | } 113 | 114 | Users tempUser = getUser(updatedUserBO.getId()); 115 | if (tempUser.getCanImoocNumBeUpdated() == YesOrNo.NO.type) { 116 | GraceException.display(ResponseStatusEnum.USER_INFO_CANT_UPDATED_IMOOCNUM_ERROR); 117 | } 118 | 119 | updatedUserBO.setCanImoocNumBeUpdated(YesOrNo.NO.type); 120 | } 121 | 122 | return updateUserInfo(updatedUserBO); 123 | 124 | } 125 | } 126 | --------------------------------------------------------------------------------