diff --git a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/CommentController.java b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/CommentController.java index 106c50b60..18b95b576 100644 --- a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/CommentController.java +++ b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/CommentController.java @@ -1,8 +1,12 @@ package com.wzj.soopin.consumer.content.controller; +import com.wzj.soopin.content.domain.base.BaseInfoProperties; import com.wzj.soopin.content.domain.bo.CommentBO; +import com.wzj.soopin.content.domain.po.Comment; +import com.wzj.soopin.content.domain.po.Vlog; import com.wzj.soopin.content.domain.vo.CommentVO; +import com.wzj.soopin.content.enums.MessageEnum; import com.wzj.soopin.content.service.CommentService; import com.wzj.soopin.content.service.MsgService; import com.wzj.soopin.content.service.VlogService; @@ -18,11 +22,13 @@ import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; + + @Slf4j @Api(tags = "CommentController 评论模块的接口") @RequestMapping("comment") @RestController -public class CommentController extends BaseController { +public class CommentController extends BaseInfoProperties { @Autowired private CommentService commentService; diff --git a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/FansController.java b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/FansController.java index bfc51a1ec..4ea440dc6 100644 --- a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/FansController.java +++ b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/FansController.java @@ -3,13 +3,13 @@ package com.wzj.soopin.consumer.content.controller; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import com.imooc.base.BaseInfoProperties; -import com.imooc.grace.result.GraceJSONResult; -import com.imooc.grace.result.ResponseStatusEnum; -import com.imooc.pojo.Users; -import com.imooc.service.FansService; -import com.imooc.service.UserService; -import io.swagger.annotations.Api; + +import com.wzj.soopin.content.domain.base.BaseInfoProperties; +import com.wzj.soopin.content.domain.po.Users; +import com.wzj.soopin.content.result.GraceJSONResult; +import com.wzj.soopin.content.result.ResponseStatusEnum; +import com.wzj.soopin.content.service.FansService; +import com.wzj.soopin.content.service.UserService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; diff --git a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/FileController.java b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/FileController.java index aa47fb9b6..fa4b2c91c 100644 --- a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/FileController.java +++ b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/FileController.java @@ -1,9 +1,9 @@ package com.wzj.soopin.consumer.content.controller; -import com.imooc.config.MinIOConfig; -import com.imooc.grace.result.GraceJSONResult; -import io.swagger.annotations.Api; + +import com.wzj.soopin.consumer.content.config.MinIOConfig; +import com.wzj.soopin.content.result.GraceJSONResult; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; diff --git a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/MsgController.java b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/MsgController.java index b074e2916..086d8a7f9 100644 --- a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/MsgController.java +++ b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/MsgController.java @@ -1,9 +1,9 @@ package com.wzj.soopin.consumer.content.controller; -import com.imooc.base.BaseInfoProperties; -import com.imooc.grace.result.GraceJSONResult; -import com.imooc.mo.MessageMO; -import com.imooc.service.MsgService; +import com.wzj.soopin.content.domain.base.BaseInfoProperties; +import com.wzj.soopin.content.domain.mo.MessageMO; +import com.wzj.soopin.content.result.GraceJSONResult; +import com.wzj.soopin.content.service.MsgService; import io.swagger.annotations.Api; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; diff --git a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/PassportController.java b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/PassportController.java index cacd9a533..b8a9062d1 100644 --- a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/PassportController.java +++ b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/PassportController.java @@ -1,17 +1,20 @@ package com.wzj.soopin.consumer.content.controller; -import com.imooc.base.BaseInfoProperties; -import com.imooc.bo.LoginWithPasswordBO; -import com.imooc.bo.RegistLoginBO; -import com.imooc.grace.result.GraceJSONResult; -import com.imooc.grace.result.ResponseStatusEnum; -import com.imooc.pojo.Users; -import com.imooc.service.UserService; -import com.imooc.utils.GsonUtil; -import com.imooc.utils.IPUtil; -import com.imooc.utils.SMSUtils; -import com.imooc.vo.UsersVO; + +import com.wzj.soopin.content.domain.base.BaseInfoProperties; +import com.wzj.soopin.content.domain.bo.LoginWithPasswordBO; +import com.wzj.soopin.content.domain.bo.RegistLoginBO; +import com.wzj.soopin.content.domain.po.Users; +import com.wzj.soopin.content.domain.vo.UsersVO; +import com.wzj.soopin.content.result.GraceJSONResult; +import com.wzj.soopin.content.result.ResponseStatusEnum; +import com.wzj.soopin.content.service.UserService; +import com.wzj.soopin.content.utils.GsonUtil; +import com.wzj.soopin.content.utils.IPUtil; +import com.wzj.soopin.content.utils.SMSUtils; import io.swagger.annotations.Api; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; @@ -19,8 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; + import java.util.Optional; import java.util.UUID; diff --git a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/RabbitMQConsumer.java b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/RabbitMQConsumer.java index ea3cd50c9..52402edd1 100644 --- a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/RabbitMQConsumer.java +++ b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/RabbitMQConsumer.java @@ -1,12 +1,12 @@ package com.wzj.soopin.consumer.content.controller; -import com.imooc.base.RabbitMQConfig; -import com.imooc.enums.MessageEnum; -import com.imooc.exceptions.GraceException; -import com.imooc.grace.result.ResponseStatusEnum; -import com.imooc.mo.MessageMO; -import com.imooc.service.MsgService; -import com.imooc.utils.JsonUtils; + +import com.wzj.soopin.content.domain.base.RabbitMQConfig; +import com.wzj.soopin.content.domain.exceptions.GraceException; +import com.wzj.soopin.content.domain.mo.MessageMO; +import com.wzj.soopin.content.enums.MessageEnum; +import com.wzj.soopin.content.service.MsgService; +import com.wzj.soopin.content.utils.JsonUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; diff --git a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/UserInfoController.java b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/UserInfoController.java index 0433cf7db..00364ae24 100644 --- a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/UserInfoController.java +++ b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/UserInfoController.java @@ -1,16 +1,16 @@ package com.wzj.soopin.consumer.content.controller; -import com.imooc.base.BaseInfoProperties; -import com.imooc.bo.UpdatedUserBO; -import com.imooc.config.MinIOConfig; -import com.imooc.enums.FileTypeEnum; -import com.imooc.enums.UserInfoModifyType; -import com.imooc.grace.result.GraceJSONResult; -import com.imooc.grace.result.ResponseStatusEnum; -import com.imooc.pojo.Users; -import com.imooc.service.UserService; -import com.imooc.utils.MinIOUtils; -import com.imooc.vo.UsersVO; + +import com.wzj.soopin.consumer.content.config.MinIOConfig; +import com.wzj.soopin.content.domain.base.BaseInfoProperties; +import com.wzj.soopin.content.domain.bo.UpdatedUserBO; +import com.wzj.soopin.content.domain.po.Users; +import com.wzj.soopin.content.domain.vo.UsersVO; +import com.wzj.soopin.content.enums.FileTypeEnum; +import com.wzj.soopin.content.enums.UserInfoModifyType; +import com.wzj.soopin.content.result.GraceJSONResult; +import com.wzj.soopin.content.result.ResponseStatusEnum; +import com.wzj.soopin.content.service.UserService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; diff --git a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/VlogController.java b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/VlogController.java index 2c8c41c67..b30f450aa 100644 --- a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/VlogController.java +++ b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/controller/VlogController.java @@ -1,20 +1,18 @@ package com.wzj.soopin.consumer.content.controller; -import com.imooc.base.BaseInfoProperties; -import com.imooc.bo.VlogBO; -import com.imooc.config.MinIOConfig; -import com.imooc.enums.YesOrNo; -import com.imooc.grace.result.GraceJSONResult; -import com.imooc.service.VlogService; -import com.imooc.utils.PagedGridResult; -import com.imooc.utils.QcCloud; + +import com.wzj.soopin.consumer.content.config.MinIOConfig; +import com.wzj.soopin.content.domain.base.BaseInfoProperties; +import com.wzj.soopin.content.domain.bo.VlogBO; +import com.wzj.soopin.content.result.GraceJSONResult; +import com.wzj.soopin.content.service.VlogService; import io.swagger.annotations.Api; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.cloud.context.config.annotation.RefreshScope; + import org.springframework.web.bind.annotation.*; import java.util.List; diff --git a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/intercepter/PassportInterceptor.java b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/intercepter/PassportInterceptor.java index e636282e8..a6446b1c4 100644 --- a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/intercepter/PassportInterceptor.java +++ b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/intercepter/PassportInterceptor.java @@ -1,15 +1,13 @@ package com.wzj.soopin.consumer.content.intercepter; -import com.imooc.base.BaseInfoProperties; -import com.imooc.exceptions.GraceException; -import com.imooc.grace.result.ResponseStatusEnum; -import com.imooc.utils.IPUtil; + +import com.wzj.soopin.content.domain.base.BaseInfoProperties; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; @Slf4j public class PassportInterceptor extends BaseInfoProperties implements HandlerInterceptor { diff --git a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/intercepter/UserTokenInterceptor.java b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/intercepter/UserTokenInterceptor.java index 382ca5075..c195b5b5b 100644 --- a/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/intercepter/UserTokenInterceptor.java +++ b/ruoyi-front/ruoyi-consumer/src/main/java/com/wzj/soopin/consumer/content/intercepter/UserTokenInterceptor.java @@ -1,15 +1,14 @@ package com.wzj.soopin.consumer.content.intercepter; -import com.imooc.base.BaseInfoProperties; -import com.imooc.exceptions.GraceException; -import com.imooc.grace.result.ResponseStatusEnum; + +import com.wzj.soopin.content.domain.base.BaseInfoProperties; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; @Slf4j public class UserTokenInterceptor extends BaseInfoProperties implements HandlerInterceptor { diff --git a/ruoyi-modules/ruoyi-content/pom.xml b/ruoyi-modules/ruoyi-content/pom.xml index e4545e86d..e73cf50d0 100644 --- a/ruoyi-modules/ruoyi-content/pom.xml +++ b/ruoyi-modules/ruoyi-content/pom.xml @@ -14,6 +14,23 @@ + + org.springframework.boot + spring-boot-starter-amqp + + + + com.tencentcloudapi + tencentcloud-sdk-java + 3.1.270 + + + + + com.qcloud + vod_api + 2.1.5 + org.dromara @@ -97,6 +114,17 @@ org.dromara ruoyi-common-sse + + com.github.pagehelper + pagehelper + 5.3.2 + compile + + + com.squareup.okhttp3 + okhttp + 4.12.0 + diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/base/BaseInfoProperties.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/base/BaseInfoProperties.java new file mode 100644 index 000000000..d355e136f --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/base/BaseInfoProperties.java @@ -0,0 +1,64 @@ +package com.wzj.soopin.content.domain.base; + + + + +import com.github.pagehelper.PageInfo; +import com.wzj.soopin.content.utils.PagedGridResult; +import com.wzj.soopin.content.utils.RedisOperator; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + +public class BaseInfoProperties { + + @Autowired + public RedisOperator redis; + + public static final Integer COMMON_START_PAGE = 1; + public static final Integer COMMON_START_PAGE_ZERO = 0; + public static final Integer COMMON_PAGE_SIZE = 10; + + public static final String MOBILE_SMSCODE = "mobile:smscode"; + public static final String REDIS_USER_TOKEN = "redis_user_token"; + public static final String REDIS_USER_INFO = "redis_user_info"; + + // 短视频的评论总数 + public static final String REDIS_VLOG_COMMENT_COUNTS = "redis_vlog_comment_counts"; + // 短视频的评论喜欢数量 + public static final String REDIS_VLOG_COMMENT_LIKED_COUNTS = "redis_vlog_comment_liked_counts"; + // 用户点赞评论 + public static final String REDIS_USER_LIKE_COMMENT = "redis_user_like_comment"; + + + //我的关注总数 + public static final String REDIS_MY_FOLLOWS_COUNTS = "redis_my_follows_counts"; + // 我的粉丝总数 + public static final String REDIS_MY_FANS_COUNTS = "redis_my_fans_counts"; + + // 视频和发布者获赞数 + public static final String REDIS_VLOG_BE_LIKED_COUNTS = "redis_vlog_be_liked_counts"; + public static final String REDIS_VLOGER_BE_LIKED_COUNTS = "redis_vloger_be_liked_counts"; + + // 博主和粉丝的关联关系,用于判断他们是否互粉 + public static final String REDIS_FANS_AND_VLOGGER_RELATIONSHIP = "redis_fans_and_vlogger_relationship"; + // 拉黑 + public static final String REDIS_USER_BLOCK = "redis_user_block"; + // 举报视频 + public static final String REDIS_VIDEO_BLOCK = "redis_video_block"; + + + // 用户是否喜欢/点赞视频,取代数据库的关联关系,1:喜欢,0:不喜欢(默认) redis_user_like_vlog:{userId}:{vlogId} + public static final String REDIS_USER_LIKE_VLOG = "redis_user_like_vlog"; + + public PagedGridResult setterPagedGrid(List list, Integer page) { + PageInfo pageList = new PageInfo<>(list); + PagedGridResult gridResult = new PagedGridResult(); + gridResult.setRows(list); + gridResult.setPage(page); + gridResult.setRecords(pageList.getTotal()); + gridResult.setTotal(pageList.getPages()); + return gridResult; + } + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/base/RabbitMQConfig.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/base/RabbitMQConfig.java new file mode 100644 index 000000000..61d58ec07 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/base/RabbitMQConfig.java @@ -0,0 +1,55 @@ +package com.wzj.soopin.content.domain.base;//package com.imooc; + + +import org.springframework.amqp.core.*; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + + + +@Configuration +public class RabbitMQConfig { + + /** + * 根据模型编写代码: + * 1. 定义交换机 + * 2. 定义队列 + * 3. 创建交换机 + * 4. 创建队列 + * 5. 队列和交换机的绑定 + */ + + public static final String EXCHANGE_MSG = "exchange_msg"; + + public static final String QUEUE_SYS_MSG = "queue_sys_msg"; + + @Bean(EXCHANGE_MSG) + public Exchange exchange() { + return ExchangeBuilder // 构建交换机 + .topicExchange(EXCHANGE_MSG) // 使用topic类型,参考:https://www.rabbitmq.com/getstarted.html + .durable(true) // 设置持久化,重启mq后依然存在 + .build(); + } + + @Bean(QUEUE_SYS_MSG) + public Queue queue() { + return new Queue(QUEUE_SYS_MSG); + } + + @Bean + public Binding binding(@Qualifier(EXCHANGE_MSG) Exchange exchange, + @Qualifier(QUEUE_SYS_MSG) Queue queue) { + + return BindingBuilder + .bind(queue) + .to(exchange) + .with("sys.msg.*") // 定义路由规则(requestMapping) + .noargs(); + + // FIXME: * 和 # 分别代表什么意思? + } + + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/exceptions/GraceException.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/exceptions/GraceException.java new file mode 100644 index 000000000..0d3e52bf2 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/exceptions/GraceException.java @@ -0,0 +1,14 @@ +package com.wzj.soopin.content.domain.exceptions; + +import com.imooc.grace.result.ResponseStatusEnum; + +/** + * 优雅的处理异常,统一封装 + */ +public class GraceException { + + public static void display(ResponseStatusEnum responseStatusEnum) { + throw new MyCustomException(responseStatusEnum); + } + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/exceptions/GraceExceptionHandler.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/exceptions/GraceExceptionHandler.java new file mode 100644 index 000000000..735a04d93 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/exceptions/GraceExceptionHandler.java @@ -0,0 +1,58 @@ +package com.wzj.soopin.content.domain.exceptions; + +import com.imooc.grace.result.GraceJSONResult; +import com.imooc.grace.result.ResponseStatusEnum; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.multipart.MaxUploadSizeExceededException; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 统一异常拦截处理 + * 可以针对异常的类型进行捕获,然后返回json信息到前端 + */ +@ControllerAdvice +public class GraceExceptionHandler { + + @ExceptionHandler(MyCustomException.class) + @ResponseBody + public GraceJSONResult returnMyException(MyCustomException e) { + //e.printStackTrace(); + return GraceJSONResult.exception(e.getResponseStatusEnum()); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseBody + public GraceJSONResult returnMethodArgumentNotValid(MethodArgumentNotValidException e) { + BindingResult result = e.getBindingResult(); + Map map = getErrors(result); + return GraceJSONResult.errorMap(map); + } + + @ExceptionHandler(MaxUploadSizeExceededException.class) + @ResponseBody + public GraceJSONResult returnMaxUploadSize(MaxUploadSizeExceededException e) { +// e.printStackTrace(); + return GraceJSONResult.errorCustom(ResponseStatusEnum.FILE_MAX_SIZE_2MB_ERROR); + } + + public Map getErrors(BindingResult result) { + Map map = new HashMap<>(); + List errorList = result.getFieldErrors(); + for (FieldError ff : errorList) { + // 错误所对应的属性字段名 + String field = ff.getField(); + // 错误的信息 + String msg = ff.getDefaultMessage(); + map.put(field, msg); + } + return map; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/exceptions/MyCustomException.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/exceptions/MyCustomException.java new file mode 100644 index 000000000..c8d9ac898 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/exceptions/MyCustomException.java @@ -0,0 +1,28 @@ +package com.wzj.soopin.content.domain.exceptions; + +import com.imooc.grace.result.ResponseStatusEnum; + +/** + * 自定义异常 + * 目的:统一处理异常信息 + * 便于解耦,拦截器、service与controller 异常错误的解耦, + * 不会被service返回的类型而限制 + */ +public class MyCustomException extends RuntimeException { + + private ResponseStatusEnum responseStatusEnum; + + public MyCustomException(ResponseStatusEnum responseStatusEnum) { + super("异常状态码为:" + responseStatusEnum.status() + + ";具体异常信息为:" + responseStatusEnum.msg()); + this.responseStatusEnum = responseStatusEnum; + } + + public ResponseStatusEnum getResponseStatusEnum() { + return responseStatusEnum; + } + + public void setResponseStatusEnum(ResponseStatusEnum responseStatusEnum) { + this.responseStatusEnum = responseStatusEnum; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/mo/MessageMO.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/mo/MessageMO.java index a4a00d416..f7c4ac514 100644 --- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/mo/MessageMO.java +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/mo/MessageMO.java @@ -1,5 +1,6 @@ package com.wzj.soopin.content.domain.mo; +import com.baomidou.mybatisplus.annotation.TableField; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -19,21 +20,21 @@ public class MessageMO { @Id private String id; // 消息主键id - @Field("fromUserId") + @TableField("fromUserId") private String fromUserId; // 消息来自的用户id - @Field("fromNickname") + @TableField("fromNickname") private String fromNickname; // 消息来自的用户昵称 - @Field("fromFace") + @TableField("fromFace") private String fromFace; // 消息来自的用户头像 - @Field("toUserId") + @TableField("toUserId") private String toUserId; // 消息发送到某对象的用户id - @Field("msgType") + @TableField("msgType") private Integer msgType; // 消息类型 枚举 - @Field("msgContent") + @TableField("msgContent") private Map msgContent; // 消息内容 - @Field("createTime") + @TableField("createTime") private Date createTime; // 消息创建时间 } diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/result/GraceJSONResult.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/result/GraceJSONResult.java new file mode 100644 index 000000000..28a8e0309 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/result/GraceJSONResult.java @@ -0,0 +1,153 @@ +package com.wzj.soopin.content.domain.result; + +import java.util.Map; + +/** + * 自定义响应数据类型枚举升级版本 + * + * @Title: IMOOCJSONResult.java + * @Package com.imooc.utils + * @Description: 自定义响应数据结构 + * 本类可提供给 H5/ios/安卓/公众号/小程序 使用 + * 前端接受此类数据(json object)后,可自行根据业务去实现相关功能 + * + * @Copyright: Copyright (c) 2020 + * @Company: www.imooc.com + * @author 慕课网 - 风间影月 + * @version V2.0 + */ +public class GraceJSONResult { + + // 响应业务状态码 + private Integer status; + + // 响应消息 + private String msg; + + // 是否成功 + private Boolean success; + + // 响应数据,可以是Object,也可以是List或Map等 + private Object data; + + /** + * 成功返回,带有数据的,直接往OK方法丢data数据即可 + * @param data + * @return + */ + public static GraceJSONResult ok(Object data) { + return new GraceJSONResult(data); + } + /** + * 成功返回,不带有数据的,直接调用ok方法,data无须传入(其实就是null) + * @return + */ + public static GraceJSONResult ok() { + return new GraceJSONResult(ResponseStatusEnum.SUCCESS); + } + public GraceJSONResult(Object data) { + this.status = ResponseStatusEnum.SUCCESS.status(); + this.msg = ResponseStatusEnum.SUCCESS.msg(); + this.success = ResponseStatusEnum.SUCCESS.success(); + this.data = data; + } + + + /** + * 错误返回,直接调用error方法即可,当然也可以在ResponseStatusEnum中自定义错误后再返回也都可以 + * @return + */ + public static GraceJSONResult error() { + return new GraceJSONResult(ResponseStatusEnum.FAILED); + } + + /** + * 错误返回,map中包含了多条错误信息,可以用于表单验证,把错误统一的全部返回出去 + * @param map + * @return + */ + public static GraceJSONResult errorMap(Map map) { + return new GraceJSONResult(ResponseStatusEnum.FAILED, map); + } + + /** + * 错误返回,直接返回错误的消息 + * @param msg + * @return + */ + public static GraceJSONResult errorMsg(String msg) { + return new GraceJSONResult(ResponseStatusEnum.FAILED, msg); + } + + /** + * 错误返回,token异常,一些通用的可以在这里统一定义 + * @return + */ + public static GraceJSONResult errorTicket() { + return new GraceJSONResult(ResponseStatusEnum.TICKET_INVALID); + } + + /** + * 自定义错误范围,需要传入一个自定义的枚举,可以到[ResponseStatusEnum.java[中自定义后再传入 + * @param responseStatus + * @return + */ + public static GraceJSONResult errorCustom(ResponseStatusEnum responseStatus) { + return new GraceJSONResult(responseStatus); + } + public static GraceJSONResult exception(ResponseStatusEnum responseStatus) { + return new GraceJSONResult(responseStatus); + } + + public GraceJSONResult(ResponseStatusEnum responseStatus) { + this.status = responseStatus.status(); + this.msg = responseStatus.msg(); + this.success = responseStatus.success(); + } + public GraceJSONResult(ResponseStatusEnum responseStatus, Object data) { + this.status = responseStatus.status(); + this.msg = responseStatus.msg(); + this.success = responseStatus.success(); + this.data = data; + } + public GraceJSONResult(ResponseStatusEnum responseStatus, String msg) { + this.status = responseStatus.status(); + this.msg = msg; + this.success = responseStatus.success(); + } + + public GraceJSONResult() { + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public Boolean getSuccess() { + return success; + } + + public void setSuccess(Boolean success) { + this.success = success; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/result/IMOOCJSONResult.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/result/IMOOCJSONResult.java new file mode 100644 index 000000000..cb7018f5c --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/result/IMOOCJSONResult.java @@ -0,0 +1,135 @@ +package com.wzj.soopin.content.domain.result; + +/** + * + * @Title: IMOOCJSONResult.java + * @Package com.imooc.utils + * @Description: 自定义响应数据结构 + * 本类可提供给 H5/ios/安卓/公众号/小程序 使用 + * 前端接受此类数据(json object)后,可自行根据业务去实现相关功能 + * + * 200:表示成功 + * 500:表示错误,错误信息在msg字段中 + * 501:bean验证错误,不管多少个错误都以map形式返回 + * 502:拦截器拦截到用户token出错 + * 555:异常抛出信息 + * 556: 用户qq校验异常 + * 557: 校验用户是否在CAS登录,用户门票的校验 + * @Copyright: Copyright (c) 2020 + * @Company: www.imooc.com + * @author 慕课网 - 风间影月 + * @version V1.0 + */ +public class IMOOCJSONResult { + + // 响应业务状态 + private Integer status; + + // 响应消息 + private String msg; + + // 响应中的数据 + private Object data; + + private String ok; // 不使用 + + public static IMOOCJSONResult build(Integer status, String msg, Object data) { + return new IMOOCJSONResult(status, msg, data); + } + + public static IMOOCJSONResult build(Integer status, String msg, Object data, String ok) { + return new IMOOCJSONResult(status, msg, data, ok); + } + + public static IMOOCJSONResult ok(Object data) { + return new IMOOCJSONResult(data); + } + + public static IMOOCJSONResult ok() { + return new IMOOCJSONResult(null); + } + + public static IMOOCJSONResult errorMsg(String msg) { + return new IMOOCJSONResult(500, msg, null); + } + + public static IMOOCJSONResult errorUserTicket(String msg) { + return new IMOOCJSONResult(557, msg, null); + } + + public static IMOOCJSONResult errorMap(Object data) { + return new IMOOCJSONResult(501, "error", data); + } + + public static IMOOCJSONResult errorTokenMsg(String msg) { + return new IMOOCJSONResult(502, msg, null); + } + + public static IMOOCJSONResult errorException(String msg) { + return new IMOOCJSONResult(555, msg, null); + } + + public static IMOOCJSONResult errorUserQQ(String msg) { + return new IMOOCJSONResult(556, msg, null); + } + + public IMOOCJSONResult() { + + } + + public IMOOCJSONResult(Integer status, String msg, Object data) { + this.status = status; + this.msg = msg; + this.data = data; + } + + public IMOOCJSONResult(Integer status, String msg, Object data, String ok) { + this.status = status; + this.msg = msg; + this.data = data; + this.ok = ok; + } + + public IMOOCJSONResult(Object data) { + this.status = 200; + this.msg = "OK"; + this.data = data; + } + + public Boolean isOK() { + return this.status == 200; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public String getOk() { + return ok; + } + + public void setOk(String ok) { + this.ok = ok; + } + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/result/ResponseStatusEnum.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/result/ResponseStatusEnum.java new file mode 100644 index 000000000..14dbb5638 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/result/ResponseStatusEnum.java @@ -0,0 +1,108 @@ +package com.wzj.soopin.content.domain.result; + +/** + * 响应结果枚举,用于提供给GraceJSONResult返回给前端的 + * 本枚举类中包含了很多的不同的状态码供使用,可以自定义 + * 便于更优雅的对状态码进行管理,一目了然 + */ +public enum ResponseStatusEnum { + + SUCCESS(200, true, "操作成功!"), + FAILED(500, false, "操作失败!"), + ON_BLOCK(201,false,"用户已被拉黑"), + // 50x + UN_LOGIN(501,false,"请登录后再继续操作!"), + TICKET_INVALID(502,false,"会话失效,请重新登录!"), + NO_AUTH(503,false,"您的权限不足,无法继续操作!"), + MOBILE_ERROR(504,false,"短信发送失败,请稍后重试!"), + SMS_NEED_WAIT_ERROR(505,false,"短信发送太快啦~请稍后再试!"), + SMS_CODE_ERROR(506,false,"验证码过期或不匹配,请稍后再试!"), + USER_FROZEN(507,false,"用户已被冻结,请联系管理员!"), + USER_UPDATE_ERROR(508,false,"用户信息更新失败,请联系管理员!"), + USER_INACTIVE_ERROR(509,false,"请前往[账号设置]修改信息激活后再进行后续操作!"), + USER_INFO_UPDATED_ERROR(5091,false,"用户信息修改失败!"), + USER_INFO_UPDATED_NICKNAME_EXIST_ERROR(5092,false,"昵称已经存在!"), + FANS_INFO_UPDATED_ISFAN_EXIST_ERROR(5092,false,"已关注"), + FANS_INFO_UPDATED_ISFLOW_EXIST_ERROR(5092,false,"未关注"), + USER_INFO_UPDATED_IMOOCNUM_EXIST_ERROR(5092,false,"视频号已经存在!"), + USER_INFO_CANT_UPDATED_IMOOCNUM_ERROR(5092,false,"视频号无法修改!"), + FILE_UPLOAD_NULL_ERROR(510,false,"文件不能为空,请选择一个文件再上传!"), + FILE_UPLOAD_FAILD(511,false,"文件上传失败!"), + FILE_FORMATTER_FAILD(512,false,"文件图片格式不支持!"), + FILE_MAX_SIZE_500KB_ERROR(5131,false,"仅支持500kb大小以下的图片上传!"), + FILE_MAX_SIZE_2MB_ERROR(5132,false,"仅支持2MB大小以下的图片上传!"), + FILE_NOT_EXIST_ERROR(514,false,"你所查看的文件不存在!"), + USER_STATUS_ERROR(515,false,"用户状态参数出错!"), + USER_NOT_EXIST_ERROR(516,false,"用户不存在!"), + USER_PASSWORD_ERROR(517,false,"密码错误!"), + + // 自定义系统级别异常 54x + SYSTEM_INDEX_OUT_OF_BOUNDS(541, false, "系统错误,数组越界!"), + SYSTEM_ARITHMETIC_BY_ZERO(542, false, "系统错误,无法除零!"), + SYSTEM_NULL_POINTER(543, false, "系统错误,空指针!"), + SYSTEM_NUMBER_FORMAT(544, false, "系统错误,数字转换异常!"), + SYSTEM_PARSE(545, false, "系统错误,解析异常!"), + SYSTEM_IO(546, false, "系统错误,IO输入输出异常!"), + SYSTEM_FILE_NOT_FOUND(547, false, "系统错误,文件未找到!"), + SYSTEM_CLASS_CAST(548, false, "系统错误,类型强制转换错误!"), + SYSTEM_PARSER_ERROR(549, false, "系统错误,解析出错!"), + SYSTEM_DATE_PARSER_ERROR(550, false, "系统错误,日期解析出错!"), + + // admin 管理系统 56x + ADMIN_USERNAME_NULL_ERROR(561, false, "管理员登录名不能为空!"), + ADMIN_USERNAME_EXIST_ERROR(562, false, "管理员登录名已存在!"), + ADMIN_NAME_NULL_ERROR(563, false, "管理员负责人不能为空!"), + ADMIN_PASSWORD_ERROR(564, false, "密码不能为空后者两次输入不一致!"), + ADMIN_CREATE_ERROR(565, false, "添加管理员失败!"), + ADMIN_PASSWORD_NULL_ERROR(566, false, "密码不能为空!"), + ADMIN_NOT_EXIT_ERROR(567, false, "管理员不存在或密码错误!"), + ADMIN_FACE_NULL_ERROR(568, false, "人脸信息不能为空!"), + ADMIN_FACE_LOGIN_ERROR(569, false, "人脸识别失败,请重试!"), + CATEGORY_EXIST_ERROR(570, false, "文章分类已存在,请换一个分类名!"), + + // 媒体中心 相关错误 58x + ARTICLE_COVER_NOT_EXIST_ERROR(580, false, "文章封面不存在,请选择一个!"), + ARTICLE_CATEGORY_NOT_EXIST_ERROR(581, false, "请选择正确的文章领域!"), + ARTICLE_CREATE_ERROR(582, false, "创建文章失败,请重试或联系管理员!"), + ARTICLE_QUERY_PARAMS_ERROR(583, false, "文章列表查询参数错误!"), + ARTICLE_DELETE_ERROR(584, false, "文章删除失败!"), + ARTICLE_WITHDRAW_ERROR(585, false, "文章撤回失败!"), + ARTICLE_REVIEW_ERROR(585, false, "文章审核出错!"), + ARTICLE_ALREADY_READ_ERROR(586, false, "文章重复阅读!"), + + // 人脸识别错误代码 + FACE_VERIFY_TYPE_ERROR(600, false, "人脸比对验证类型不正确!"), + FACE_VERIFY_LOGIN_ERROR(601, false, "人脸登录失败!"), + + // 系统错误,未预期的错误 555 + SYSTEM_ERROR(555, false, "系统繁忙,请稍后再试!"), + SYSTEM_OPERATION_ERROR(556, false, "操作失败,请重试或联系管理员"), + SYSTEM_RESPONSE_NO_INFO(557, false, ""), + SYSTEM_ERROR_GLOBAL(558, false, "全局降级:系统繁忙,请稍后再试!"), + SYSTEM_ERROR_FEIGN(559, false, "客户端Feign降级:系统繁忙,请稍后再试!"), + SYSTEM_ERROR_ZUUL(560, false, "请求系统过于繁忙,请稍后再试!"); + + + // 响应业务状态 + private Integer status; + // 调用是否成功 + private Boolean success; + // 响应消息,可以为成功或者失败的消息 + private String msg; + + ResponseStatusEnum(Integer status, Boolean success, String msg) { + this.status = status; + this.success = success; + this.msg = msg; + } + + public Integer status() { + return status; + } + public Boolean success() { + return success; + } + public String msg() { + return msg; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/FileTypeEnum.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/FileTypeEnum.java new file mode 100644 index 000000000..14379f4da --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/FileTypeEnum.java @@ -0,0 +1,17 @@ +package com.wzj.soopin.content.enums; + +/** + * @Desc: 文件类型 枚举 + */ +public enum FileTypeEnum { + BGIMG(1, "用户背景图"), + FACE(2, "用户头像"); + + public final Integer type; + public final String value; + + FileTypeEnum(Integer type, String value) { + this.type = type; + this.value = value; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/MessageEnum.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/MessageEnum.java new file mode 100644 index 000000000..32a0f7386 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/MessageEnum.java @@ -0,0 +1,22 @@ +package com.wzj.soopin.content.enums; + +/** + * @Desc: 消息类型 + */ +public enum MessageEnum { + FOLLOW_YOU(1, "关注", "follow"), + LIKE_VLOG(2, "点赞视频", "likeVideo"), + COMMENT_VLOG(3, "评论视频", "comment"), + REPLY_YOU(4, "回复评论", "replay"), + LIKE_COMMENT(5, "点赞评论", "likeComment"); + + public final Integer type; + public final String value; + public final String enValue; + + MessageEnum(Integer type, String value, String enValue) { + this.type = type; + this.value = value; + this.enValue = enValue; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/Sex.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/Sex.java new file mode 100644 index 000000000..1e1d33831 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/Sex.java @@ -0,0 +1,18 @@ +package com.wzj.soopin.content.enums; + +/** + * @Desc: 性别 枚举 + */ +public enum Sex { + woman(0, "女"), + man(1, "男"), + secret(2, "保密"); + + public final Integer type; + public final String value; + + Sex(Integer type, String value) { + this.type = type; + this.value = value; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/UserInfoModifyType.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/UserInfoModifyType.java new file mode 100644 index 000000000..ae29d469a --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/UserInfoModifyType.java @@ -0,0 +1,35 @@ +package com.wzj.soopin.content.enums; + +import com.imooc.exceptions.GraceException; +import com.imooc.grace.result.ResponseStatusEnum; + +/** + * @Desc: 修改用户信息类型 枚举 + */ +public enum UserInfoModifyType { + NICKNAME(1, "昵称"), + IMOOCNUM(2, "慕课号"), + SEX(3, "性别"), + BIRTHDAY(4, "生日"), + LOCATION(5, "所在地"), + DESC(6, "简介"); + + public final Integer type; + public final String value; + + UserInfoModifyType(Integer type, String value) { + this.type = type; + this.value = value; + } + + public static void checkUserInfoTypeIsRight(Integer type) { + if (type != UserInfoModifyType.NICKNAME.type && + type != UserInfoModifyType.IMOOCNUM.type && + type != UserInfoModifyType.SEX.type && + type != UserInfoModifyType.BIRTHDAY.type && + type != UserInfoModifyType.LOCATION.type && + type != UserInfoModifyType.DESC.type) { + GraceException.display(ResponseStatusEnum.USER_INFO_UPDATED_ERROR); + } + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/YesOrNo.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/YesOrNo.java new file mode 100644 index 000000000..4d0a0d643 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/enums/YesOrNo.java @@ -0,0 +1,17 @@ +package com.wzj.soopin.content.enums; + +/** + * @Desc: 是否 枚举 + */ +public enum YesOrNo { + NO(0, "否"), + YES(1, "是"); + + public final Integer type; + public final String value; + + YesOrNo(Integer type, String value) { + this.type = type; + this.value = value; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/Code.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/Code.java new file mode 100644 index 000000000..13cc01c81 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/Code.java @@ -0,0 +1,35 @@ +package com.wzj.soopin.content.idworker; + +import org.n3r.idworker.strategy.DefaultRandomCodeStrategy; + +public class Code { + private static RandomCodeStrategy strategy; + + static { + RandomCodeStrategy strategy = new DefaultRandomCodeStrategy(); + strategy.init(); + configure(strategy); + } + + public static synchronized void configure(RandomCodeStrategy custom) { + if (strategy == custom) return; + if (strategy != null) strategy.release(); + + strategy = custom; + } + + /** + * Next Unique code. + * The max length will be 1024-Integer.MAX-Integer.MAX(2147483647) which has 4+10+10+2*1=26 characters. + * The min length will be 0-0. + * + * @return unique string code. + */ + public static synchronized String next() { + long workerId = Id.getWorkerId(); + int prefix = strategy.prefix(); + int next = strategy.next(); + + return String.format("%d-%03d-%06d", workerId, prefix, next); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/DayCode.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/DayCode.java new file mode 100644 index 000000000..f9170b651 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/DayCode.java @@ -0,0 +1,19 @@ +package com.wzj.soopin.content.idworker; + +import org.n3r.idworker.strategy.DayPrefixRandomCodeStrategy; + +public class DayCode { + static RandomCodeStrategy strategy; + + static { + DayPrefixRandomCodeStrategy dayPrefixCodeStrategy = new DayPrefixRandomCodeStrategy("yyMM"); + dayPrefixCodeStrategy.setMinRandomSize(7); + dayPrefixCodeStrategy.setMaxRandomSize(7); + strategy = dayPrefixCodeStrategy; + strategy.init(); + } + + public static synchronized String next() { + return String.format("%d-%04d-%07d", Id.getWorkerId(), strategy.prefix(), strategy.next()); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/Id.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/Id.java new file mode 100644 index 000000000..9368a15c0 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/Id.java @@ -0,0 +1,29 @@ +package com.wzj.soopin.content.idworker; + +import org.n3r.idworker.strategy.DefaultWorkerIdStrategy; + +public class Id { + private static WorkerIdStrategy workerIdStrategy; + private static IdWorker idWorker; + + static { + configure(DefaultWorkerIdStrategy.instance); + } + + public static synchronized void configure(WorkerIdStrategy custom) { + if (workerIdStrategy == custom) return; + + if (workerIdStrategy != null) workerIdStrategy.release(); + workerIdStrategy = custom; + workerIdStrategy.initialize(); + idWorker = new IdWorker(workerIdStrategy.availableWorkerId()); + } + + public static long next() { + return idWorker.nextId(); + } + + public static long getWorkerId() { + return idWorker.getWorkerId(); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/IdWorker.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/IdWorker.java new file mode 100644 index 000000000..235b1a314 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/IdWorker.java @@ -0,0 +1,91 @@ +package com.wzj.soopin.content.idworker; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.SecureRandom; + +public class IdWorker { + protected long epoch = 1288834974657L; +// protected long epoch = 1387886498127L; // 2013-12-24 20:01:38.127 + + + protected long workerIdBits = 10L; + protected long maxWorkerId = -1L ^ (-1L << workerIdBits); + protected long sequenceBits = 11L; + + protected long workerIdShift = sequenceBits; + protected long timestampLeftShift = sequenceBits + workerIdBits; + protected long sequenceMask = -1L ^ (-1L << sequenceBits); + + protected long lastMillis = -1L; + + protected final long workerId; + protected long sequence = 0L; + protected Logger logger = LoggerFactory.getLogger(IdWorker.class); + + public IdWorker(long workerId) { + this.workerId = checkWorkerId(workerId); + + logger.debug("worker starting. timestamp left shift {}, worker id {}", timestampLeftShift, workerId); + } + + public long getEpoch() { + return epoch; + } + + private long checkWorkerId(long workerId) { + // sanity check for workerId + if (workerId > maxWorkerId || workerId < 0) { + int rand = new SecureRandom().nextInt((int) maxWorkerId + 1); + logger.warn("worker Id can't be greater than {} or less than 0, use a random {}", maxWorkerId, rand); + return rand; + } + + return workerId; + } + + public synchronized long nextId() { + long timestamp = millisGen(); + + if (timestamp < lastMillis) { + logger.error("clock is moving backwards. Rejecting requests until {}.", lastMillis); + throw new InvalidSystemClock(String.format( + "Clock moved backwards. Refusing to generate id for {} milliseconds", lastMillis - timestamp)); + } + + if (lastMillis == timestamp) { + sequence = (sequence + 1) & sequenceMask; + if (sequence == 0) + timestamp = tilNextMillis(lastMillis); + } else { + sequence = 0; + } + + lastMillis = timestamp; + long diff = timestamp - getEpoch(); + return (diff << timestampLeftShift) | + (workerId << workerIdShift) | + sequence; + } + + protected long tilNextMillis(long lastMillis) { + long millis = millisGen(); + while (millis <= lastMillis) + millis = millisGen(); + + return millis; + } + + protected long millisGen() { + return System.currentTimeMillis(); + } + + public long getLastMillis() { + return lastMillis; + } + + public long getWorkerId() { + return workerId; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/InvalidSystemClock.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/InvalidSystemClock.java new file mode 100644 index 000000000..f83465a20 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/InvalidSystemClock.java @@ -0,0 +1,7 @@ +package com.wzj.soopin.content.idworker; + +public class InvalidSystemClock extends RuntimeException { + public InvalidSystemClock(String message) { + super(message); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/RandomCodeStrategy.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/RandomCodeStrategy.java new file mode 100644 index 000000000..6a25fbeb0 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/RandomCodeStrategy.java @@ -0,0 +1,11 @@ +package com.wzj.soopin.content.idworker; + +public interface RandomCodeStrategy { + void init(); + + int prefix(); + + int next(); + + void release(); +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/Sid.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/Sid.java new file mode 100644 index 000000000..de0a5329f --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/Sid.java @@ -0,0 +1,64 @@ +package com.wzj.soopin.content.idworker; + +import org.n3r.idworker.strategy.DefaultWorkerIdStrategy; +import org.n3r.idworker.utils.Utils; +import org.springframework.stereotype.Component; + +import java.text.SimpleDateFormat; +import java.util.Date; + +@Component +public class Sid { + private static WorkerIdStrategy workerIdStrategy; + private static IdWorker idWorker; + + static { + configure(DefaultWorkerIdStrategy.instance); + } + + + public static synchronized void configure(WorkerIdStrategy custom) { + if (workerIdStrategy != null) { + workerIdStrategy.release(); + } + workerIdStrategy = custom; + idWorker = new IdWorker(workerIdStrategy.availableWorkerId()) { + @Override + public long getEpoch() { + return Utils.midnightMillis(); + } + }; + } + + /** + * 一天最大毫秒86400000,最大占用27比特 + * 27+10+11=48位 最大值281474976710655(15字),YK0XXHZ827(10字) + * 6位(YYMMDD)+15位,共21位 + * + * @return 固定21位数字字符串 + */ + + public static String next() { + long id = idWorker.nextId(); + String yyMMdd = new SimpleDateFormat("yyMMdd").format(new Date()); + return yyMMdd + String.format("%014d", id); + } + + + /** + * 返回固定16位的字母数字混编的字符串。 + */ + public String nextShort() { + long id = idWorker.nextId(); + String yyMMdd = new SimpleDateFormat("yyMMdd").format(new Date()); + return yyMMdd + Utils.padLeft(Utils.encode(id), 10, '0'); + } + + public static void main(String[] args) { + String aa = new Sid().nextShort(); + String bb = new Sid().next(); + + System.out.println(aa); + System.out.println(bb); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/Test.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/Test.java new file mode 100644 index 000000000..cd6f73523 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/Test.java @@ -0,0 +1,12 @@ +package com.wzj.soopin.content.idworker; + +public class Test { + + public static void main(String[] args) { + + for (int i = 0 ; i < 1000 ; i ++) { +// System.out.println(Sid.nextShort()); + } + } + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/WorkerIdStrategy.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/WorkerIdStrategy.java new file mode 100644 index 000000000..6bd66ff3b --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/WorkerIdStrategy.java @@ -0,0 +1,9 @@ +package com.wzj.soopin.content.idworker; + +public interface WorkerIdStrategy { + void initialize(); + + long availableWorkerId(); + + void release(); +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/strategy/DayPrefixRandomCodeStrategy.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/strategy/DayPrefixRandomCodeStrategy.java new file mode 100644 index 000000000..7f1981afe --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/strategy/DayPrefixRandomCodeStrategy.java @@ -0,0 +1,41 @@ +package com.wzj.soopin.content.idworker.strategy; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class DayPrefixRandomCodeStrategy extends DefaultRandomCodeStrategy { + private final String dayFormat; + private String lastDay; + + public DayPrefixRandomCodeStrategy(String dayFormat) { + this.dayFormat = dayFormat; + } + + @Override + public void init() { + String day = createDate(); + if (day.equals(lastDay)) + throw new RuntimeException("init failed for day unrolled"); + + lastDay = day; + + availableCodes.clear(); + release(); + + prefixIndex = Integer.parseInt(lastDay); + if (tryUsePrefix()) return; + + throw new RuntimeException("prefix is not available " + prefixIndex); + } + + private String createDate() { + return new SimpleDateFormat(dayFormat).format(new Date()); + } + + @Override + public int next() { + if (!lastDay.equals(createDate())) init(); + + return super.next(); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/strategy/DefaultRandomCodeStrategy.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/strategy/DefaultRandomCodeStrategy.java new file mode 100644 index 000000000..f903942cb --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/strategy/DefaultRandomCodeStrategy.java @@ -0,0 +1,197 @@ +package com.wzj.soopin.content.idworker.strategy; + +import org.n3r.idworker.Id; +import org.n3r.idworker.RandomCodeStrategy; +import org.n3r.idworker.utils.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.security.SecureRandom; +import java.util.ArrayDeque; +import java.util.BitSet; +import java.util.Queue; + +public class DefaultRandomCodeStrategy implements RandomCodeStrategy { + public static final int MAX_BITS = 1000000; + + Logger log = LoggerFactory.getLogger(DefaultRandomCodeStrategy.class); + + File idWorkerHome = Utils.createIdWorkerHome(); + volatile FileLock fileLock; + BitSet codesFilter; + + int prefixIndex = -1; + File codePrefixIndex; + + int minRandomSize = 6; + int maxRandomSize = 6; + + public DefaultRandomCodeStrategy() { + destroyFileLockWhenShutdown(); + } + + @Override + public void init() { + release(); + + while (++prefixIndex < 1000) { + if (tryUsePrefix()) return; + } + + throw new RuntimeException("all prefixes are used up, the world maybe ends!"); + } + + public DefaultRandomCodeStrategy setMinRandomSize(int minRandomSize) { + this.minRandomSize = minRandomSize; + return this; + } + + public DefaultRandomCodeStrategy setMaxRandomSize(int maxRandomSize) { + this.maxRandomSize = maxRandomSize; + return this; + } + + protected boolean tryUsePrefix() { + codePrefixIndex = new File(idWorkerHome, Id.getWorkerId() + ".code.prefix." + prefixIndex); + + if (!createPrefixIndexFile()) return false; + if (!createFileLock()) return false; + if (!createBloomFilter()) return false; + + log.info("get available prefix index file {}", codePrefixIndex); + + return true; + } + + private boolean createFileLock() { + if (fileLock != null) fileLock.destroy(); + fileLock = new FileLock(codePrefixIndex); + return fileLock.tryLock(); + } + + private boolean createBloomFilter() { + codesFilter = fileLock.readObject(); + if (codesFilter == null) { + log.info("create new bloom filter"); + codesFilter = new BitSet(MAX_BITS); // 2^24 + } else { + int size = codesFilter.cardinality(); + if (size >= MAX_BITS) { + log.warn("bloom filter with prefix file {} is already full", codePrefixIndex); + return false; + } + log.info("recreate bloom filter with cardinality {}", size); + } + + return true; + } + + private void destroyFileLockWhenShutdown() { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + release(); + } + }); + } + + private boolean createPrefixIndexFile() { + try { + codePrefixIndex.createNewFile(); + return codePrefixIndex.exists(); + } catch (IOException e) { + e.printStackTrace(); + log.warn("create file {} error {}", codePrefixIndex, e.getMessage()); + } + return false; + } + + @Override + public int prefix() { + return prefixIndex; + } + + static final int CACHE_CODES_NUM = 1000; + + SecureRandom secureRandom = new SecureRandom(); + Queue availableCodes = new ArrayDeque(CACHE_CODES_NUM); + + @Override + public int next() { + if (availableCodes.isEmpty()) generate(); + + return availableCodes.poll(); + } + + @Override + public synchronized void release() { + if (fileLock != null) { + fileLock.writeObject(codesFilter); + fileLock.destroy(); + fileLock = null; + } + } + + private void generate() { + for (int i = 0; i < CACHE_CODES_NUM; ++i) + availableCodes.add(generateOne()); + + fileLock.writeObject(codesFilter); + } + + private int generateOne() { + while (true) { + int code = secureRandom.nextInt(max(maxRandomSize)); + boolean existed = contains(code); + + code = !existed ? add(code) : tryFindAvailableCode(code); + if (code >= 0) return code; + + init(); + } + } + + private int tryFindAvailableCode(int code) { + int next = codesFilter.nextClearBit(code); + if (next != -1 && next < max(maxRandomSize)) return add(next); + + next = codesFilter.previousClearBit(code); + if (next != -1) return add(next); + + return -1; + } + + private int add(int code) { + codesFilter.set(code); + return code; + } + + private boolean contains(int code) { + return codesFilter.get(code); + } + + + private int max(int size) { + switch (size) { + case 1: // fall through + case 2: // fall through + case 3: // fall through + case 4: + return 10000; + case 5: + return 100000; + case 6: + return 1000000; + case 7: + return 10000000; + case 8: + return 100000000; + case 9: + return 1000000000; + default: + return Integer.MAX_VALUE; + } + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/strategy/DefaultWorkerIdStrategy.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/strategy/DefaultWorkerIdStrategy.java new file mode 100644 index 000000000..b0372941c --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/strategy/DefaultWorkerIdStrategy.java @@ -0,0 +1,205 @@ +package com.wzj.soopin.content.idworker.strategy; + +import org.n3r.idworker.WorkerIdStrategy; +import org.n3r.idworker.utils.HttpReq; +import org.n3r.idworker.utils.Ip; +import org.n3r.idworker.utils.Props; +import org.n3r.idworker.utils.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.security.SecureRandom; +import java.util.Properties; +import java.util.Random; + +public class DefaultWorkerIdStrategy implements WorkerIdStrategy { + static long workerIdBits = 10L; + static long maxWorkerId = -1L ^ (-1L << workerIdBits); + static Random random = new SecureRandom(); + + public static final WorkerIdStrategy instance = new DefaultWorkerIdStrategy(); + + private final Properties props = + Props.tryProperties("idworker-client.properties", Utils.DOT_IDWORKERS); + private final String idWorkerServerUrl = + props.getProperty("server.address", "http://id.worker.server:18001"); + + String userName = System.getProperty("user.name"); + + String ipDotUsername = Ip.ip + "." + userName; + String ipudotlock = ipDotUsername + ".lock."; + int workerIdIndex = ipudotlock.length(); + long workerId; + FileLock fileLock; + + Logger logger = LoggerFactory.getLogger(DefaultWorkerIdStrategy.class); + private boolean inited; + + + private void init() { + workerId = findAvailWorkerId(); + if (workerId >= 0) { + destroyFileLockWhenShutdown(); + startSyncThread(); + } else { + syncWithWorkerIdServer(); + workerId = findAvailWorkerId(); + if (workerId < 0) workerId = increaseWithWorkerIdServer(); + } + + if (workerId < 0) workerId = tryToCreateOnIp(); + if (workerId < 0) { + logger.warn("DANGEROUS!!! Try to use random worker id."); + workerId = tryToRandomOnIp(); // Try avoiding! it could cause duplicated + } + + if (workerId < 0) { + logger.warn("the world may be ended!"); + throw new RuntimeException("the world may be ended"); + } + } + + private void destroyFileLockWhenShutdown() { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + fileLock.destroy(); + } + }); + } + + private void startSyncThread() { + new Thread() { + @Override + public void run() { + syncWithWorkerIdServer(); + } + }.start(); + } + + private long increaseWithWorkerIdServer() { + String incId = HttpReq.get(idWorkerServerUrl) + .req("/inc") + .param("ipu", ipDotUsername) + .exec(); + if (incId == null || incId.trim().isEmpty()) return -1L; + + long lid = Long.parseLong(incId); + + return checkAvail(lid); + } + + private long tryToCreateOnIp() { + long wid = Ip.lip & maxWorkerId; + + return checkAvail(wid); + } + + private long tryToRandomOnIp() { + long avaiWorkerId = -1L; + long tryTimes = -1; + + while (avaiWorkerId < 0 && ++tryTimes < maxWorkerId) { + long wid = Ip.lip & random.nextInt((int) maxWorkerId); + + avaiWorkerId = checkAvail(wid); + } + return avaiWorkerId; + } + + private long checkAvail(long wid) { + long availWorkerId = -1L; + try { + File idWorkerHome = Utils.createIdWorkerHome(); + new File(idWorkerHome, ipudotlock + String.format("%04d", wid)).createNewFile(); + availWorkerId = findAvailWorkerId(); + } catch (IOException e) { + logger.warn("checkAvail error", e); + } + + return availWorkerId; + } + + private void syncWithWorkerIdServer() { + String syncIds = HttpReq.get(idWorkerServerUrl).req("/sync") + .param("ipu", ipDotUsername).param("ids", buildWorkerIdsOfCurrentIp()) + .exec(); + if (syncIds == null || syncIds.trim().isEmpty()) return; + + String[] syncIdsArr = syncIds.split(","); + File idWorkerHome = Utils.createIdWorkerHome(); + for (String syncId : syncIdsArr) { + try { + new File(idWorkerHome, ipudotlock + syncId).createNewFile(); + } catch (IOException e) { + logger.warn("create workerid lock file error", e); + } + } + } + + private String buildWorkerIdsOfCurrentIp() { + StringBuilder sb = new StringBuilder(); + File idWorkerHome = Utils.createIdWorkerHome(); + for (File lockFile : idWorkerHome.listFiles()) { + // check the format like 10.142.1.151.lock.0001 + if (!lockFile.getName().startsWith(ipudotlock)) continue; + + String workerId = lockFile.getName().substring(workerIdIndex); + if (!workerId.matches("\\d\\d\\d\\d")) continue; + + if (sb.length() > 0) sb.append(','); + sb.append(workerId); + } + + return sb.toString(); + } + + + /** + * Find the local available worker id. + * + * @return -1 when N/A + */ + private long findAvailWorkerId() { + File idWorkerHome = Utils.createIdWorkerHome(); + + for (File lockFile : idWorkerHome.listFiles()) { + // check the format like 10.142.1.151.lock.0001 + if (!lockFile.getName().startsWith(ipudotlock)) continue; + + String workerId = lockFile.getName().substring(workerIdIndex); + if (!workerId.matches("\\d\\d\\d\\d")) continue; + + FileLock fileLock = new FileLock(lockFile); + if (!fileLock.tryLock()) { + fileLock.destroy(); + continue; + } + + this.fileLock = fileLock; + return Long.parseLong(workerId); + } + + return -1; + } + + @Override + public void initialize() { + if (inited) return; + init(); + this.inited = true; + } + + @Override + public long availableWorkerId() { + return workerId; + } + + @Override + public void release() { + if (fileLock != null) fileLock.destroy(); + inited = false; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/strategy/FileLock.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/strategy/FileLock.java new file mode 100644 index 000000000..04017ab84 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/strategy/FileLock.java @@ -0,0 +1,132 @@ +package com.wzj.soopin.content.idworker.strategy; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.nio.channels.Channels; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.FileChannel; +import java.nio.channels.OverlappingFileLockException; + +/** + * A file lock a la flock/funlock + *

+ * The given path will be created and opened if it doesn't exist. + */ +public class FileLock { + private final File file; + private FileChannel channel; + private java.nio.channels.FileLock flock = null; + Logger logger = LoggerFactory.getLogger(FileLock.class); + + public FileLock(File file) { + this.file = file; + + try { + file.createNewFile(); // create the file if it doesn't exist + channel = new RandomAccessFile(file, "rw").getChannel(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + /** + * Lock the file or throw an exception if the lock is already held + */ + public void lock() { + try { + synchronized (this) { + logger.trace("Acquiring lock on {}", file.getAbsolutePath()); + flock = channel.lock(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Try to lock the file and return true if the locking succeeds + */ + public boolean tryLock() { + synchronized (this) { + logger.trace("Acquiring lock on {}", file.getAbsolutePath()); + try { + // weirdly this method will return null if the lock is held by another + // process, but will throw an exception if the lock is held by this process + // so we have to handle both cases + flock = channel.tryLock(); + return flock != null; + } catch (OverlappingFileLockException e) { + return false; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + /** + * Unlock the lock if it is held + */ + public void unlock() { + synchronized (this) { + logger.trace("Releasing lock on {}", file.getAbsolutePath()); + if (flock == null) return; + try { + flock.release(); + } catch (ClosedChannelException e) { + // Ignore + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + /** + * Destroy this lock, closing the associated FileChannel + */ + public void destroy() { + synchronized (this) { + unlock(); + if (!channel.isOpen()) return; + + try { + channel.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + + @SuppressWarnings("unchecked") + public T readObject() { + try { + InputStream is = Channels.newInputStream(channel); + ObjectInputStream objectReader = new ObjectInputStream(is); + return (T) objectReader.readObject(); + } catch (EOFException e) { + } catch (Exception e) { + throw new RuntimeException(e); + } + + return null; + } + + + public synchronized boolean writeObject(Object object) { + if (!channel.isOpen()) return false; + + try { + channel.position(0); + OutputStream out = Channels.newOutputStream(channel); + ObjectOutputStream objectOutput = new ObjectOutputStream(out); + objectOutput.writeObject(object); + return true; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/HttpReq.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/HttpReq.java new file mode 100644 index 000000000..5218ae0e3 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/HttpReq.java @@ -0,0 +1,115 @@ +package com.wzj.soopin.content.idworker.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; + +public class HttpReq { + private final String baseUrl; + private String req; + private StringBuilder params = new StringBuilder(); + Logger logger = LoggerFactory.getLogger(HttpReq.class); + + public HttpReq(String baseUrl) { + this.baseUrl = baseUrl; + } + + public static HttpReq get(String baseUrl) { + return new HttpReq(baseUrl); + } + + public HttpReq req(String req) { + this.req = req; + return this; + } + + public HttpReq param(String name, String value) { + if (params.length() > 0) params.append('&'); + try { + params.append(name).append('=').append(URLEncoder.encode(value, "UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + + return this; + } + + public String exec() { + HttpURLConnection http = null; + try { + http = (HttpURLConnection) new URL(baseUrl + + (req == null ? "" : req) + + (params.length() > 0 ? ("?" + params) : "")).openConnection(); + http.setRequestProperty("Accept-Charset", "UTF-8"); + HttpURLConnection.setFollowRedirects(false); + http.setConnectTimeout(5 * 1000); + http.setReadTimeout(5 * 1000); + http.connect(); + + int status = http.getResponseCode(); + String charset = getCharset(http.getHeaderField("Content-Type")); + + if (status == 200) { + return readResponseBody(http, charset); + } else { + logger.warn("non 200 respoonse :" + readErrorResponseBody(http, status, charset)); + return null; + } + } catch (Exception e) { + logger.error("exec error {}", e.getMessage()); + return null; + } finally { + if (http != null) http.disconnect(); + } + + } + + private static String readErrorResponseBody(HttpURLConnection http, int status, String charset) throws IOException { + InputStream errorStream = http.getErrorStream(); + if (errorStream != null) { + String error = toString(charset, errorStream); + return ("STATUS CODE =" + status + "\n\n" + error); + } else { + return ("STATUS CODE =" + status); + } + } + + private static String readResponseBody(HttpURLConnection http, String charset) throws IOException { + InputStream inputStream = http.getInputStream(); + + return toString(charset, inputStream); + } + + private static String toString(String charset, InputStream inputStream) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + + int length; + while ((length = inputStream.read(buffer)) != -1) { + baos.write(buffer, 0, length); + } + + return new String(baos.toByteArray(), charset); + } + + private static String getCharset(String contentType) { + if (contentType == null) return "UTF-8"; + + String charset = null; + for (String param : contentType.replace(" ", "").split(";")) { + if (param.startsWith("charset=")) { + charset = param.split("=", 2)[1]; + break; + } + } + + return charset == null ? "UTF-8" : charset; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/IPv4Utils.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/IPv4Utils.java new file mode 100644 index 000000000..32f57f5ae --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/IPv4Utils.java @@ -0,0 +1 @@ +package com.wzj.soopin.content.idworker.utils; diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/Ip.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/Ip.java new file mode 100644 index 000000000..cafaf0cc9 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/Ip.java @@ -0,0 +1,50 @@ +package com.wzj.soopin.content.idworker.utils; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; + +public class Ip { + static Logger logger = LoggerFactory.getLogger(Ip.class); + + public static String ip; + public static long lip; + + static { + try { + InetAddress localHostLANAddress = getFirstNonLoopbackAddress(); + ip = localHostLANAddress.getHostAddress(); + + byte[] address = localHostLANAddress.getAddress(); + lip = ((address [0] & 0xFFL) << (3*8)) + + ((address [1] & 0xFFL) << (2*8)) + + ((address [2] & 0xFFL) << (1*8)) + + (address [3] & 0xFFL); + } catch (Exception e) { + logger.error("get ipv4 failed ", e); + } + } + + private static InetAddress getFirstNonLoopbackAddress() throws SocketException { + Enumeration en = NetworkInterface.getNetworkInterfaces(); + while (en.hasMoreElements()) { + NetworkInterface i = (NetworkInterface) en.nextElement(); + for (Enumeration en2 = i.getInetAddresses(); en2.hasMoreElements(); ) { + InetAddress addr = (InetAddress) en2.nextElement(); + if (addr.isLoopbackAddress()) continue; + + if (addr instanceof Inet4Address) { + return addr; + } + } + } + return null; + } + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/Props.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/Props.java new file mode 100644 index 000000000..16c869e66 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/Props.java @@ -0,0 +1,70 @@ +package com.wzj.soopin.content.idworker.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.util.Properties; + +import static java.io.File.separator; +import static org.n3r.idworker.utils.Serializes.closeQuietly; + +public class Props { + static Logger log = LoggerFactory.getLogger(Props.class); + + public static Properties tryProperties(String propertiesFileName, String userHomeBasePath) { + Properties properties = new Properties(); + InputStream is = null; + try { + is = Props.tryResource(propertiesFileName, userHomeBasePath, Silent.ON); + if (is != null) properties.load(is); + } catch (IOException e) { + log.error("load properties error: {}", e.getMessage()); + } finally { + closeQuietly(is); + } + + return properties; + } + + + enum Silent {ON, OFF} + + public static InputStream tryResource(String propertiesFileName, String userHomeBasePath, Silent silent) { + InputStream is = currentDirResource(new File(propertiesFileName)); + if (is != null) return is; + + is = userHomeResource(propertiesFileName, userHomeBasePath); + if (is != null) return is; + + is = classpathResource(propertiesFileName); + if (is != null || silent == Silent.ON) return is; + + throw new RuntimeException("fail to find " + propertiesFileName + " in current dir or classpath"); + } + + private static InputStream userHomeResource(String pathname, String appHome) { + String filePath = System.getProperty("user.home") + separator + appHome; + File dir = new File(filePath); + if (!dir.exists()) return null; + + return currentDirResource(new File(dir, pathname)); + } + + private static InputStream currentDirResource(File file) { + if (!file.exists()) return null; + + try { + return new FileInputStream(file); + } catch (FileNotFoundException e) { + // This should not happened + log.error("read file {} error", file, e); + return null; + } + } + + public static InputStream classpathResource(String resourceName) { + return Props.class.getClassLoader().getResourceAsStream(resourceName); + } + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/Serializes.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/Serializes.java new file mode 100644 index 000000000..3b78ee548 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/Serializes.java @@ -0,0 +1,118 @@ +package com.wzj.soopin.content.idworker.utils; + +import java.io.*; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.List; + +public class Serializes { + + @SuppressWarnings("unchecked") + public static List readObjects(File file) { + ArrayList objects = new ArrayList(); + ObjectInputStream objectReader = null; + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + objectReader = new ObjectInputStream(fis); + while (true) + objects.add((T) objectReader.readObject()); + + } catch (EOFException e) { + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + closeQuietly(objectReader); + closeQuietly(fis); + } + + return objects; + } + + + @SuppressWarnings("unchecked") + public static T readObject(File file) { + ObjectInputStream objectReader = null; + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + objectReader = new ObjectInputStream(fis); + return (T) objectReader.readObject(); + + } catch (EOFException e) { + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + closeQuietly(objectReader); + closeQuietly(fis); + } + + return null; + } + + public static void writeObject(File file, Object object) { + ObjectOutputStream objectOutput = null; + FileOutputStream fos = null; + try { + fos = new FileOutputStream(file); + objectOutput = new ObjectOutputStream(fos); + objectOutput.writeObject(object); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + closeQuietly(objectOutput); + closeQuietly(fos); + } + } + + public static void writeObject(FileOutputStream fos, Object object) { + FileChannel channel = fos.getChannel(); + if (!channel.isOpen()) throw new RuntimeException("channel is closed"); + + try { + channel.position(0); + ObjectOutputStream objectOutput = new ObjectOutputStream(fos); + objectOutput.writeObject(object); + fos.flush(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + } + } + + public static void writeObjects(File file, Object... objects) { + ObjectOutputStream objectOutput = null; + FileOutputStream fos = null; + try { + fos = new FileOutputStream(file); + objectOutput = new ObjectOutputStream(fos); + + for (Object object : objects) + objectOutput.writeObject(object); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + closeQuietly(objectOutput); + closeQuietly(fos); + } + + } + + public static void closeQuietly(OutputStream os) { + if (os != null) try { + os.close(); + } catch (IOException e) { + // ignore + } + } + + + public static void closeQuietly(InputStream is) { + if (is != null) try { + is.close(); + } catch (IOException e) { + // ignore + } + + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/Utils.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/Utils.java new file mode 100644 index 000000000..eca2fa470 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/idworker/utils/Utils.java @@ -0,0 +1,114 @@ +package com.wzj.soopin.content.idworker.utils; + +import java.io.*; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.Calendar; + +public class Utils { + + public static final String DOT_IDWORKERS = ".idworkers"; + + public static ClassLoader getClassLoader() { + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + return contextClassLoader != null ? contextClassLoader : Utils.class.getClassLoader(); + } + + + public static InputStream classResourceToStream(String resourceName) { + return getClassLoader().getResourceAsStream(resourceName); + } + + + public static String firstLine(String classResourceName) { + InputStream inputStream = null; + try { + inputStream = classResourceToStream(classResourceName); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); + + return bufferedReader.readLine(); + } catch (IOException e) { + return null; + } finally { + if (inputStream != null) try { + inputStream.close(); + } catch (IOException e) { + // ignore + } + } + } + + public static String checkNotEmpty(String param, String name) { + if (param == null || param.isEmpty()) + throw new IllegalArgumentException(name + " is empty"); + + return param; + } + + + public static long midnightMillis() { + // today + Calendar date = Calendar.getInstance(); + // reset hour, minutes, seconds and millis + date.set(Calendar.HOUR_OF_DAY, 0); + date.set(Calendar.MINUTE, 0); + date.set(Calendar.SECOND, 0); + date.set(Calendar.MILLISECOND, 0); + + return date.getTimeInMillis(); + } + + public static void main(String[] args) { + // 2013-12-25 00:00:00.000 + System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Timestamp(midnightMillis()))); + System.out.println(encode(281474976710655L)); + } + + public static long decode(String s, String symbols) { + final int B = symbols.length(); + long num = 0; + for (char ch : s.toCharArray()) { + num *= B; + num += symbols.indexOf(ch); + } + return num; + } + + public static String encode(long num) { + return encode(num, defaultRange); + } + + public static String encode(long num, String symbols) { + final int B = symbols.length(); + StringBuilder sb = new StringBuilder(); + while (num != 0) { + sb.append(symbols.charAt((int) (num % B))); + num /= B; + } + return sb.reverse().toString(); + } + + // all un-clearly-recognized letters are skiped. + static String defaultRange = "0123456789ABCDFGHKMNPRSTWXYZ"; + + public static String padLeft(String str, int size, char padChar) { + if (str.length() >= size) return str; + + StringBuilder s = new StringBuilder(); + for (int i = size - str.length(); i > 0; --i) { + s.append(padChar); + } + s.append(str); + + return s.toString(); + } + + public static File createIdWorkerHome() { + String userHome = System.getProperty("user.home"); + File idWorkerHome = new File(userHome + File.separator + DOT_IDWORKERS); + idWorkerHome.mkdirs(); + if (idWorkerHome.isDirectory()) return idWorkerHome; + + throw new RuntimeException("failed to create .idworkers at user home"); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/result/GraceJSONResult.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/result/GraceJSONResult.java new file mode 100644 index 000000000..d9e4f8630 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/result/GraceJSONResult.java @@ -0,0 +1,153 @@ +package com.wzj.soopin.content.result; + +import java.util.Map; + +/** + * 自定义响应数据类型枚举升级版本 + * + * @Title: IMOOCJSONResult.java + * @Package com.imooc.utils + * @Description: 自定义响应数据结构 + * 本类可提供给 H5/ios/安卓/公众号/小程序 使用 + * 前端接受此类数据(json object)后,可自行根据业务去实现相关功能 + * + * @Copyright: Copyright (c) 2020 + * @Company: www.imooc.com + * @author 慕课网 - 风间影月 + * @version V2.0 + */ +public class GraceJSONResult { + + // 响应业务状态码 + private Integer status; + + // 响应消息 + private String msg; + + // 是否成功 + private Boolean success; + + // 响应数据,可以是Object,也可以是List或Map等 + private Object data; + + /** + * 成功返回,带有数据的,直接往OK方法丢data数据即可 + * @param data + * @return + */ + public static GraceJSONResult ok(Object data) { + return new GraceJSONResult(data); + } + /** + * 成功返回,不带有数据的,直接调用ok方法,data无须传入(其实就是null) + * @return + */ + public static GraceJSONResult ok() { + return new GraceJSONResult(ResponseStatusEnum.SUCCESS); + } + public GraceJSONResult(Object data) { + this.status = ResponseStatusEnum.SUCCESS.status(); + this.msg = ResponseStatusEnum.SUCCESS.msg(); + this.success = ResponseStatusEnum.SUCCESS.success(); + this.data = data; + } + + + /** + * 错误返回,直接调用error方法即可,当然也可以在ResponseStatusEnum中自定义错误后再返回也都可以 + * @return + */ + public static GraceJSONResult error() { + return new GraceJSONResult(ResponseStatusEnum.FAILED); + } + + /** + * 错误返回,map中包含了多条错误信息,可以用于表单验证,把错误统一的全部返回出去 + * @param map + * @return + */ + public static GraceJSONResult errorMap(Map map) { + return new GraceJSONResult(ResponseStatusEnum.FAILED, map); + } + + /** + * 错误返回,直接返回错误的消息 + * @param msg + * @return + */ + public static GraceJSONResult errorMsg(String msg) { + return new GraceJSONResult(ResponseStatusEnum.FAILED, msg); + } + + /** + * 错误返回,token异常,一些通用的可以在这里统一定义 + * @return + */ + public static GraceJSONResult errorTicket() { + return new GraceJSONResult(ResponseStatusEnum.TICKET_INVALID); + } + + /** + * 自定义错误范围,需要传入一个自定义的枚举,可以到[ResponseStatusEnum.java[中自定义后再传入 + * @param responseStatus + * @return + */ + public static GraceJSONResult errorCustom(ResponseStatusEnum responseStatus) { + return new GraceJSONResult(responseStatus); + } + public static GraceJSONResult exception(ResponseStatusEnum responseStatus) { + return new GraceJSONResult(responseStatus); + } + + public GraceJSONResult(ResponseStatusEnum responseStatus) { + this.status = responseStatus.status(); + this.msg = responseStatus.msg(); + this.success = responseStatus.success(); + } + public GraceJSONResult(ResponseStatusEnum responseStatus, Object data) { + this.status = responseStatus.status(); + this.msg = responseStatus.msg(); + this.success = responseStatus.success(); + this.data = data; + } + public GraceJSONResult(ResponseStatusEnum responseStatus, String msg) { + this.status = responseStatus.status(); + this.msg = msg; + this.success = responseStatus.success(); + } + + public GraceJSONResult() { + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public Boolean getSuccess() { + return success; + } + + public void setSuccess(Boolean success) { + this.success = success; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/result/IMOOCJSONResult.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/result/IMOOCJSONResult.java new file mode 100644 index 000000000..4617b88c0 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/result/IMOOCJSONResult.java @@ -0,0 +1,135 @@ +package com.wzj.soopin.content.result; + +/** + * + * @Title: IMOOCJSONResult.java + * @Package com.imooc.utils + * @Description: 自定义响应数据结构 + * 本类可提供给 H5/ios/安卓/公众号/小程序 使用 + * 前端接受此类数据(json object)后,可自行根据业务去实现相关功能 + * + * 200:表示成功 + * 500:表示错误,错误信息在msg字段中 + * 501:bean验证错误,不管多少个错误都以map形式返回 + * 502:拦截器拦截到用户token出错 + * 555:异常抛出信息 + * 556: 用户qq校验异常 + * 557: 校验用户是否在CAS登录,用户门票的校验 + * @Copyright: Copyright (c) 2020 + * @Company: www.imooc.com + * @author 慕课网 - 风间影月 + * @version V1.0 + */ +public class IMOOCJSONResult { + + // 响应业务状态 + private Integer status; + + // 响应消息 + private String msg; + + // 响应中的数据 + private Object data; + + private String ok; // 不使用 + + public static IMOOCJSONResult build(Integer status, String msg, Object data) { + return new IMOOCJSONResult(status, msg, data); + } + + public static IMOOCJSONResult build(Integer status, String msg, Object data, String ok) { + return new IMOOCJSONResult(status, msg, data, ok); + } + + public static IMOOCJSONResult ok(Object data) { + return new IMOOCJSONResult(data); + } + + public static IMOOCJSONResult ok() { + return new IMOOCJSONResult(null); + } + + public static IMOOCJSONResult errorMsg(String msg) { + return new IMOOCJSONResult(500, msg, null); + } + + public static IMOOCJSONResult errorUserTicket(String msg) { + return new IMOOCJSONResult(557, msg, null); + } + + public static IMOOCJSONResult errorMap(Object data) { + return new IMOOCJSONResult(501, "error", data); + } + + public static IMOOCJSONResult errorTokenMsg(String msg) { + return new IMOOCJSONResult(502, msg, null); + } + + public static IMOOCJSONResult errorException(String msg) { + return new IMOOCJSONResult(555, msg, null); + } + + public static IMOOCJSONResult errorUserQQ(String msg) { + return new IMOOCJSONResult(556, msg, null); + } + + public IMOOCJSONResult() { + + } + + public IMOOCJSONResult(Integer status, String msg, Object data) { + this.status = status; + this.msg = msg; + this.data = data; + } + + public IMOOCJSONResult(Integer status, String msg, Object data, String ok) { + this.status = status; + this.msg = msg; + this.data = data; + this.ok = ok; + } + + public IMOOCJSONResult(Object data) { + this.status = 200; + this.msg = "OK"; + this.data = data; + } + + public Boolean isOK() { + return this.status == 200; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public String getOk() { + return ok; + } + + public void setOk(String ok) { + this.ok = ok; + } + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/result/ResponseStatusEnum.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/result/ResponseStatusEnum.java new file mode 100644 index 000000000..47527b3ed --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/result/ResponseStatusEnum.java @@ -0,0 +1,108 @@ +package com.wzj.soopin.content.result; + +/** + * 响应结果枚举,用于提供给GraceJSONResult返回给前端的 + * 本枚举类中包含了很多的不同的状态码供使用,可以自定义 + * 便于更优雅的对状态码进行管理,一目了然 + */ +public enum ResponseStatusEnum { + + SUCCESS(200, true, "操作成功!"), + FAILED(500, false, "操作失败!"), + ON_BLOCK(201,false,"用户已被拉黑"), + // 50x + UN_LOGIN(501,false,"请登录后再继续操作!"), + TICKET_INVALID(502,false,"会话失效,请重新登录!"), + NO_AUTH(503,false,"您的权限不足,无法继续操作!"), + MOBILE_ERROR(504,false,"短信发送失败,请稍后重试!"), + SMS_NEED_WAIT_ERROR(505,false,"短信发送太快啦~请稍后再试!"), + SMS_CODE_ERROR(506,false,"验证码过期或不匹配,请稍后再试!"), + USER_FROZEN(507,false,"用户已被冻结,请联系管理员!"), + USER_UPDATE_ERROR(508,false,"用户信息更新失败,请联系管理员!"), + USER_INACTIVE_ERROR(509,false,"请前往[账号设置]修改信息激活后再进行后续操作!"), + USER_INFO_UPDATED_ERROR(5091,false,"用户信息修改失败!"), + USER_INFO_UPDATED_NICKNAME_EXIST_ERROR(5092,false,"昵称已经存在!"), + FANS_INFO_UPDATED_ISFAN_EXIST_ERROR(5092,false,"已关注"), + FANS_INFO_UPDATED_ISFLOW_EXIST_ERROR(5092,false,"未关注"), + USER_INFO_UPDATED_IMOOCNUM_EXIST_ERROR(5092,false,"视频号已经存在!"), + USER_INFO_CANT_UPDATED_IMOOCNUM_ERROR(5092,false,"视频号无法修改!"), + FILE_UPLOAD_NULL_ERROR(510,false,"文件不能为空,请选择一个文件再上传!"), + FILE_UPLOAD_FAILD(511,false,"文件上传失败!"), + FILE_FORMATTER_FAILD(512,false,"文件图片格式不支持!"), + FILE_MAX_SIZE_500KB_ERROR(5131,false,"仅支持500kb大小以下的图片上传!"), + FILE_MAX_SIZE_2MB_ERROR(5132,false,"仅支持2MB大小以下的图片上传!"), + FILE_NOT_EXIST_ERROR(514,false,"你所查看的文件不存在!"), + USER_STATUS_ERROR(515,false,"用户状态参数出错!"), + USER_NOT_EXIST_ERROR(516,false,"用户不存在!"), + USER_PASSWORD_ERROR(517,false,"密码错误!"), + + // 自定义系统级别异常 54x + SYSTEM_INDEX_OUT_OF_BOUNDS(541, false, "系统错误,数组越界!"), + SYSTEM_ARITHMETIC_BY_ZERO(542, false, "系统错误,无法除零!"), + SYSTEM_NULL_POINTER(543, false, "系统错误,空指针!"), + SYSTEM_NUMBER_FORMAT(544, false, "系统错误,数字转换异常!"), + SYSTEM_PARSE(545, false, "系统错误,解析异常!"), + SYSTEM_IO(546, false, "系统错误,IO输入输出异常!"), + SYSTEM_FILE_NOT_FOUND(547, false, "系统错误,文件未找到!"), + SYSTEM_CLASS_CAST(548, false, "系统错误,类型强制转换错误!"), + SYSTEM_PARSER_ERROR(549, false, "系统错误,解析出错!"), + SYSTEM_DATE_PARSER_ERROR(550, false, "系统错误,日期解析出错!"), + + // admin 管理系统 56x + ADMIN_USERNAME_NULL_ERROR(561, false, "管理员登录名不能为空!"), + ADMIN_USERNAME_EXIST_ERROR(562, false, "管理员登录名已存在!"), + ADMIN_NAME_NULL_ERROR(563, false, "管理员负责人不能为空!"), + ADMIN_PASSWORD_ERROR(564, false, "密码不能为空后者两次输入不一致!"), + ADMIN_CREATE_ERROR(565, false, "添加管理员失败!"), + ADMIN_PASSWORD_NULL_ERROR(566, false, "密码不能为空!"), + ADMIN_NOT_EXIT_ERROR(567, false, "管理员不存在或密码错误!"), + ADMIN_FACE_NULL_ERROR(568, false, "人脸信息不能为空!"), + ADMIN_FACE_LOGIN_ERROR(569, false, "人脸识别失败,请重试!"), + CATEGORY_EXIST_ERROR(570, false, "文章分类已存在,请换一个分类名!"), + + // 媒体中心 相关错误 58x + ARTICLE_COVER_NOT_EXIST_ERROR(580, false, "文章封面不存在,请选择一个!"), + ARTICLE_CATEGORY_NOT_EXIST_ERROR(581, false, "请选择正确的文章领域!"), + ARTICLE_CREATE_ERROR(582, false, "创建文章失败,请重试或联系管理员!"), + ARTICLE_QUERY_PARAMS_ERROR(583, false, "文章列表查询参数错误!"), + ARTICLE_DELETE_ERROR(584, false, "文章删除失败!"), + ARTICLE_WITHDRAW_ERROR(585, false, "文章撤回失败!"), + ARTICLE_REVIEW_ERROR(585, false, "文章审核出错!"), + ARTICLE_ALREADY_READ_ERROR(586, false, "文章重复阅读!"), + + // 人脸识别错误代码 + FACE_VERIFY_TYPE_ERROR(600, false, "人脸比对验证类型不正确!"), + FACE_VERIFY_LOGIN_ERROR(601, false, "人脸登录失败!"), + + // 系统错误,未预期的错误 555 + SYSTEM_ERROR(555, false, "系统繁忙,请稍后再试!"), + SYSTEM_OPERATION_ERROR(556, false, "操作失败,请重试或联系管理员"), + SYSTEM_RESPONSE_NO_INFO(557, false, ""), + SYSTEM_ERROR_GLOBAL(558, false, "全局降级:系统繁忙,请稍后再试!"), + SYSTEM_ERROR_FEIGN(559, false, "客户端Feign降级:系统繁忙,请稍后再试!"), + SYSTEM_ERROR_ZUUL(560, false, "请求系统过于繁忙,请稍后再试!"); + + + // 响应业务状态 + private Integer status; + // 调用是否成功 + private Boolean success; + // 响应消息,可以为成功或者失败的消息 + private String msg; + + ResponseStatusEnum(Integer status, Boolean success, String msg) { + this.status = status; + this.success = success; + this.msg = msg; + } + + public Integer status() { + return status; + } + public Boolean success() { + return success; + } + public String msg() { + return msg; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/FansService.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/FansService.java index b3c99f4d1..9387c0fff 100644 --- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/FansService.java +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/FansService.java @@ -1,6 +1,6 @@ package com.wzj.soopin.content.service; -import com.imooc.utils.PagedGridResult; + import com.wzj.soopin.content.domain.vo.FansVO; import org.dromara.common.mybatis.core.page.TableDataInfo; diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/MsgService.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/MsgService.java index 151e0dcfb..61553e207 100644 --- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/MsgService.java +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/MsgService.java @@ -1,6 +1,7 @@ package com.wzj.soopin.content.service; import com.imooc.mo.MessageMO; +import com.wzj.soopin.content.domain.mo.MessageMO; import java.util.List; import java.util.Map; diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/UserService.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/UserService.java index b4d894ca1..e3cebb2bd 100644 --- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/UserService.java +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/UserService.java @@ -1,9 +1,10 @@ package com.wzj.soopin.content.service; -import com.imooc.bo.UpdatedUserBO; -import com.imooc.mo.Token; -import com.imooc.pojo.Users; -import com.imooc.vo.UsersVO; + +import com.wzj.soopin.content.domain.bo.UpdatedUserBO; +import com.wzj.soopin.content.domain.mo.Token; +import com.wzj.soopin.content.domain.po.Users; +import com.wzj.soopin.content.domain.vo.UsersVO; import java.util.List; import java.util.Map; @@ -25,8 +26,8 @@ public interface UserService { public Users createUser(String mobile); /** - * 根据用户主键查询用户信息 - */ + * 根据用户主键查询用户信息 + */ public Users getUser(String userId); /** diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/VlogService.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/VlogService.java index 99e14250d..473d5fd9c 100644 --- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/VlogService.java +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/VlogService.java @@ -4,6 +4,7 @@ import com.imooc.bo.VlogBO; import com.imooc.pojo.Vlog; import com.imooc.utils.PagedGridResult; import com.imooc.vo.IndexVlogVO; +import com.wzj.soopin.content.domain.po.Vlog; public interface VlogService { /** diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/CommentServiceImpl.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/CommentServiceImpl.java index 0b60d41e8..0899f0fd8 100644 --- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/CommentServiceImpl.java +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/CommentServiceImpl.java @@ -1,21 +1,19 @@ package com.wzj.soopin.content.service.impl; -import com.github.pagehelper.PageHelper; -import com.imooc.base.BaseInfoProperties; -import com.imooc.bo.CommentBO; -import com.imooc.enums.MessageEnum; -import com.imooc.enums.YesOrNo; -import com.imooc.mapper.CommentMapper; -import com.imooc.mapper.CommentMapperCustom; -import com.imooc.pojo.Comment; -import com.imooc.pojo.Vlog; -import com.imooc.service.CommentService; -import com.imooc.service.MsgService; -import com.imooc.service.VlogService; -import com.imooc.utils.PagedGridResult; -import com.imooc.vo.CommentVO; + + +import com.wzj.soopin.content.domain.base.BaseInfoProperties; +import com.wzj.soopin.content.domain.bo.CommentBO; +import com.wzj.soopin.content.domain.po.Comment; +import com.wzj.soopin.content.domain.po.Vlog; +import com.wzj.soopin.content.domain.vo.CommentVO; +import com.wzj.soopin.content.mapper.mapper.CommentMapper; +import com.wzj.soopin.content.mapper.mapper.CommentMapperCustom; +import com.wzj.soopin.content.service.CommentService; +import com.wzj.soopin.content.service.MsgService; +import com.wzj.soopin.content.service.VlogService; import org.apache.commons.lang3.StringUtils; -import org.n3r.idworker.Sid; + import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/MsgServiceImpl.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/MsgServiceImpl.java index f310fd9df..eba7629be 100644 --- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/MsgServiceImpl.java +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/MsgServiceImpl.java @@ -7,6 +7,7 @@ import com.imooc.pojo.Users; import com.imooc.repository.MessageRepository; import com.imooc.service.MsgService; import com.imooc.service.UserService; +import com.wzj.soopin.content.domain.mo.MessageMO; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/VlogServiceImpl.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/VlogServiceImpl.java index 5f537d368..dce694650 100644 --- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/VlogServiceImpl.java +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/VlogServiceImpl.java @@ -18,6 +18,7 @@ import com.imooc.service.MsgService; import com.imooc.service.VlogService; import com.imooc.utils.PagedGridResult; import com.imooc.vo.IndexVlogVO; +import com.wzj.soopin.content.domain.po.Vlog; import org.apache.commons.lang3.StringUtils; import org.n3r.idworker.Sid; import org.springframework.beans.BeanUtils; diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/Code.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/Code.java new file mode 100644 index 000000000..214143882 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/Code.java @@ -0,0 +1,35 @@ +package com.wzj.soopin.content.utils; + + + +public class Code { + private static RandomCodeStrategy strategy; + + static { + RandomCodeStrategy strategy = new DefaultRandomCodeStrategy(); + strategy.init(); + configure(strategy); + } + + public static synchronized void configure(RandomCodeStrategy custom) { + if (strategy == custom) return; + if (strategy != null) strategy.release(); + + strategy = custom; + } + + /** + * Next Unique code. + * The max length will be 1024-Integer.MAX-Integer.MAX(2147483647) which has 4+10+10+2*1=26 characters. + * The min length will be 0-0. + * + * @return unique string code. + */ + public static synchronized String next() { + long workerId = Id.getWorkerId(); + int prefix = strategy.prefix(); + int next = strategy.next(); + + return String.format("%d-%03d-%06d", workerId, prefix, next); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DateUtil.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DateUtil.java new file mode 100644 index 000000000..1ad38601a --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DateUtil.java @@ -0,0 +1,680 @@ +package com.wzj.soopin.content.utils; + +import org.apache.commons.lang3.StringUtils; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.*; + +public class DateUtil { + + /** + * Base ISO 8601 Date format yyyyMMdd i.e., 20021225 for the 25th day of December in the year 2002 + */ + public static final String ISO_DATE_FORMAT = "yyyyMMdd"; + + /** + * Expanded ISO 8601 Date format yyyy-MM-dd i.e., 2002-12-25 for the 25th day of December in the year 2002 + */ + public static final String ISO_EXPANDED_DATE_FORMAT = "yyyy-MM-dd"; + + /** + * yyyy-MM-dd hh:mm:ss + */ + public static String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + public static String DATE_PATTERN = "yyyyMMddHHmmss"; + + /** + * 则个 + */ + private static boolean LENIENT_DATE = false; + + + private static Random random = new Random(); + private static final int ID_BYTES = 10; + + public synchronized static String generateId() { + StringBuffer result = new StringBuffer(); + result = result.append(System.currentTimeMillis()); + for (int i = 0; i < ID_BYTES; i++) { + result = result.append(random.nextInt(10)); + } + return result.toString(); + } + + protected static final float normalizedJulian(float JD) { + + float f = Math.round(JD + 0.5f) - 0.5f; + + return f; + } + + /** + * Returns the Date from a julian. The Julian date will be converted to noon GMT, + * such that it matches the nearest half-integer (i.e., a julian date of 1.4 gets + * changed to 1.5, and 0.9 gets changed to 0.5.) + * + * @param JD the Julian date + * @return the Gregorian date + */ + public static final Date toDate(float JD) { + + /* To convert a Julian Day Number to a Gregorian date, assume that it is for 0 hours, Greenwich time (so + * that it ends in 0.5). Do the following calculations, again dropping the fractional part of all + * multiplicatons and divisions. Note: This method will not give dates accurately on the + * Gregorian Proleptic Calendar, i.e., the calendar you get by extending the Gregorian + * calendar backwards to years earlier than 1582. using the Gregorian leap year + * rules. In particular, the method fails if Y<400. */ + float Z = (normalizedJulian(JD)) + 0.5f; + float W = (int) ((Z - 1867216.25f) / 36524.25f); + float X = (int) (W / 4f); + float A = Z + 1 + W - X; + float B = A + 1524; + float C = (int) ((B - 122.1) / 365.25); + float D = (int) (365.25f * C); + float E = (int) ((B - D) / 30.6001); + float F = (int) (30.6001f * E); + int day = (int) (B - D - F); + int month = (int) (E - 1); + + if (month > 12) { + month = month - 12; + } + + int year = (int) (C - 4715); //(if Month is January or February) or C-4716 (otherwise) + + if (month > 2) { + year--; + } + + Calendar c = Calendar.getInstance(); + c.set(Calendar.YEAR, year); + c.set(Calendar.MONTH, month - 1); // damn 0 offsets + c.set(Calendar.DATE, day); + + return c.getTime(); + } + + /** + * Returns the days between two dates. Positive values indicate that + * the second date is after the first, and negative values indicate, well, + * the opposite. Relying on specific times is problematic. + * + * @param early the "first date" + * @param late the "second date" + * @return the days between the two dates + */ + public static final int daysBetween(Date early, Date late) { + + Calendar c1 = Calendar.getInstance(); + Calendar c2 = Calendar.getInstance(); + c1.setTime(early); + c2.setTime(late); + + return daysBetween(c1, c2); + } + + /** + * Returns the days between two dates. Positive values indicate that + * the second date is after the first, and negative values indicate, well, + * the opposite. + * + * @param early + * @param late + * @return the days between two dates. + */ + public static final int daysBetween(Calendar early, Calendar late) { + + return (int) (toJulian(late) - toJulian(early)); + } + + /** + * 计算时间差 + * @param startDate + * @param endDate + * @return + */ + public static final String timeBetween(Date startDate, Date endDate) { + long nd = 1000 * 24 * 60 * 60; + long nh = 1000 * 60 * 60; + long nm = 1000 * 60; + // long ns = 1000; + // 获得两个时间的毫秒时间差异 + long diff = endDate.getTime() - startDate.getTime(); + // 计算差多少天 + long day = diff / nd; + // 计算差多少小时 + long hour = diff % nd / nh; + // 计算差多少分钟 + long min = diff % nd % nh / nm; + // 计算差多少秒//输出结果 + // long sec = diff % nd % nh % nm / ns; + return day + "天" + hour + "小时" + min + "分钟"; + } + + /** + * Return a Julian date based on the input parameter. This is + * based from calculations found at + * Julian Day Calculations + * (Gregorian Calendar), provided by Bill Jeffrys. + * @param c a calendar instance + * @return the julian day number + */ + public static final float toJulian(Calendar c) { + + int Y = c.get(Calendar.YEAR); + int M = c.get(Calendar.MONTH); + int D = c.get(Calendar.DATE); + int A = Y / 100; + int B = A / 4; + int C = 2 - A + B; + float E = (int) (365.25f * (Y + 4716)); + float F = (int) (30.6001f * (M + 1)); + float JD = C + D + E + F - 1524.5f; + + return JD; + } + + /** + * Return a Julian date based on the input parameter. This is + * based from calculations found at + * Julian Day Calculations + * (Gregorian Calendar), provided by Bill Jeffrys. + * @param date + * @return the julian day number + */ + public static final float toJulian(Date date) { + + Calendar c = Calendar.getInstance(); + c.setTime(date); + + return toJulian(c); + } + + /** + * @param isoString + * @param fmt + * @param field Calendar.YEAR/Calendar.MONTH/Calendar.DATE + * @param amount + * @return + * @throws ParseException + */ + public static final String dateIncrease(String isoString, String fmt, + int field, int amount) { + + try { + Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone( + "GMT")); + cal.setTime(stringToDate(isoString, fmt, true)); + cal.add(field, amount); + + return dateToString(cal.getTime(), fmt); + + } catch (Exception ex) { + return null; + } + } + + /** + * Time Field Rolling function. + * Rolls (up/down) a single unit of time on the given time field. + * + * @param isoString + * @param field the time field. + * @param up Indicates if rolling up or rolling down the field value. + * @param expanded use formating char's + * @exception ParseException if an unknown field value is given. + */ + public static final String roll(String isoString, String fmt, int field, + boolean up) throws ParseException { + + Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone( + "GMT")); + cal.setTime(stringToDate(isoString, fmt)); + cal.roll(field, up); + + return dateToString(cal.getTime(), fmt); + } + + /** + * Time Field Rolling function. + * Rolls (up/down) a single unit of time on the given time field. + * + * @param isoString + * @param field the time field. + * @param up Indicates if rolling up or rolling down the field value. + * @exception ParseException if an unknown field value is given. + */ + public static final String roll(String isoString, int field, boolean up) throws + ParseException { + + return roll(isoString, DATETIME_PATTERN, field, up); + } + + /** + * java.util.Date + * @param dateText + * @param format + * @param lenient + * @return + */ + public static Date stringToDate(String dateText, String format, + boolean lenient) { + + if (dateText == null) { + + return null; + } + + DateFormat df = null; + + try { + + if (format == null) { + df = new SimpleDateFormat(); + } else { + df = new SimpleDateFormat(format); + } + + // setLenient avoids allowing dates like 9/32/2001 + // which would otherwise parse to 10/2/2001 + df.setLenient(false); + + return df.parse(dateText); + } catch (ParseException e) { + + return null; + } + } + + /** + * @return Timestamp + */ + public static java.sql.Timestamp getCurrentTimestamp() { + return new java.sql.Timestamp(new Date().getTime()); + } + + /** java.util.Date + * @param dateText + * @param format + * @return + */ + public static Date stringToDate(String dateString, String format) { + + return stringToDate(dateString, format, LENIENT_DATE); + } + + /** + * java.util.Date + * @param dateText + */ + public static Date stringToDate(String dateString) { + return stringToDate(dateString, ISO_EXPANDED_DATE_FORMAT, LENIENT_DATE); + } + + /** + * @return + * @param pattern + * @param date + */ + public static String dateToString(Date date, String pattern) { + + if (date == null) { + + return null; + } + + try { + + SimpleDateFormat sfDate = new SimpleDateFormat(pattern); + sfDate.setLenient(false); + + return sfDate.format(date); + } catch (Exception e) { + + return null; + } + } + + /** + * yyyy-MM-dd + * @param date + * @return + */ + public static String dateToString(Date date) { + return dateToString(date, ISO_EXPANDED_DATE_FORMAT); + } + + /** + * @return + */ + public static Date getCurrentDateTime() { + Calendar calNow = Calendar.getInstance(); + Date dtNow = calNow.getTime(); + + return dtNow; + } + + /** + * + * @param pattern + * @return + */ + public static String getCurrentDateString(String pattern) { + return dateToString(getCurrentDateTime(), pattern); + } + + /** + * yyyy-MM-dd + * @return + */ + public static String getCurrentDateString() { + return dateToString(getCurrentDateTime(), ISO_EXPANDED_DATE_FORMAT); + } + + /** + * 返回固定格式的当前时间 + * yyyy-MM-dd hh:mm:ss + * @param date + * @return + */ + public static String dateToStringWithTime( ) { + + return dateToString(new Date(), DATETIME_PATTERN); + } + + + /** + * yyyy-MM-dd hh:mm:ss + * @param date + * @return + */ + public static String dateToStringWithTime(Date date) { + + return dateToString(date, DATETIME_PATTERN); + } + + /** + * + * @param date + * @param days + * @return java.util.Date + */ + public static Date dateIncreaseByDay(Date date, int days) { + + Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone( + "GMT")); + cal.setTime(date); + cal.add(Calendar.DATE, days); + + return cal.getTime(); + } + + /** + * + * @param date + * @param days + * @return java.util.Date + */ + public static Date dateIncreaseByMonth(Date date, int mnt) { + + Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone( + "GMT")); + cal.setTime(date); + cal.add(Calendar.MONTH, mnt); + + return cal.getTime(); + } + + /** + * + * @param date + * @param mnt + * @return java.util.Date + */ + public static Date dateIncreaseByYear(Date date, int mnt) { + + Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone( + "GMT")); + cal.setTime(date); + cal.add(Calendar.YEAR, mnt); + + return cal.getTime(); + } + + /** + * + * @param date yyyy-MM-dd + * @param days + * @return yyyy-MM-dd + */ + public static String dateIncreaseByDay(String date, int days) { + return dateIncreaseByDay(date, ISO_DATE_FORMAT, days); + } + + /** + * @param date + * @param fmt + * @param days + * @return + */ + public static String dateIncreaseByDay(String date, String fmt, int days) { + return dateIncrease(date, fmt, Calendar.DATE, days); + } + + /** + * + * @param src + * @param srcfmt + * @param desfmt + * @return + */ + public static String stringToString(String src, String srcfmt, + String desfmt) { + return dateToString(stringToDate(src, srcfmt), desfmt); + } + + /** + * + * @param date + * @return string + */ + public static String getYear(Date date) { + SimpleDateFormat formater = new SimpleDateFormat( + "yyyy"); + String cur_year = formater.format(date); + return cur_year; + } + + /** + * + * @param date + * @return string + */ + public static String getMonth(Date date) { + SimpleDateFormat formater = new SimpleDateFormat( + "MM"); + String cur_month = formater.format(date); + return cur_month; + } + + /** + * @param date + * @return string + */ + public static String getDay(Date date) { + SimpleDateFormat formater = new SimpleDateFormat( + "dd"); + String cur_day = formater.format(date); + return cur_day; + } + + public static int getDayInt(Date date) { + SimpleDateFormat formater = new SimpleDateFormat( + "dd"); + String cur_day = formater.format(date); + return Integer.valueOf(cur_day); + } + + /** + * @param date + * @return string + */ + public static String getHour(Date date) { + SimpleDateFormat formater = new SimpleDateFormat( + "HH"); + String cur_day = formater.format(date); + return cur_day; + } + + public static int getMinsFromDate(Date dt) { + GregorianCalendar cal = new GregorianCalendar(); + cal.setTime(dt); + int hour = cal.get(Calendar.HOUR_OF_DAY); + int min = cal.get(Calendar.MINUTE); + return ((hour * 60) + min); + } + + /** + * Function to convert String to Date Object. If invalid input then current or next day date + * is returned (Added by Ali Naqvi on 2006-5-16). + * @param str String input in YYYY-MM-DD HH:MM[:SS] format. + * @param isExpiry boolean if set and input string is invalid then next day date is returned + * @return Date + */ + public static Date convertToDate(String str, boolean isExpiry) { + SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + Date dt = null; + try { + dt = fmt.parse(str); + } catch (ParseException ex) { + Calendar cal = Calendar.getInstance(); + if (isExpiry) { + cal.add(Calendar.DAY_OF_MONTH, 1); + cal.set(Calendar.HOUR_OF_DAY, 23); + cal.set(Calendar.MINUTE, 59); + } else { + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + } + dt = cal.getTime(); + } + return dt; + } + + public static Date convertToDate(String str) { + SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd hh:mm"); + Date dt = null; + try { + dt = fmt.parse(str); + } catch (ParseException ex) { + dt = new Date(); + } + return dt; + } + + public static String dateFromat(Date date, int minute) { + String dateFormat = null; + int year = Integer.parseInt(getYear(date)); + int month = Integer.parseInt(getMonth(date)); + int day = Integer.parseInt(getDay(date)); + int hour = minute / 60; + int min = minute % 60; + dateFormat = String.valueOf(year) + + + (month > 9 ? String.valueOf(month) : + "0" + String.valueOf(month)) + + + (day > 9 ? String.valueOf(day) : "0" + String.valueOf(day)) + + " " + + + (hour > 9 ? String.valueOf(hour) : "0" + String.valueOf(hour)) + + + (min > 9 ? String.valueOf(min) : "0" + String.valueOf(min)) + + "00"; + return dateFormat; + } + + public static String sDateFormat() { + return new SimpleDateFormat(DATE_PATTERN).format(Calendar.getInstance().getTime()); + } + + /** + * + * @Description: 获得本月的第一天日期 + * @return + * + * @author leechenxiang + * @date 2017年5月31日 下午1:37:34 + */ + public static String getFirstDateOfThisMonth() { + + SimpleDateFormat format = new SimpleDateFormat(ISO_EXPANDED_DATE_FORMAT); + + Calendar calendarFirst = Calendar.getInstance(); + calendarFirst = Calendar.getInstance(); + calendarFirst.add(Calendar.MONTH, 0); + calendarFirst.set(Calendar.DAY_OF_MONTH, 1); + String firstDate = format.format(calendarFirst.getTime()); + + return firstDate; + } + + /** + * + * @Description: 获得本月的最后一天日期 + * @return + * + * @author leechenxiang + * @date 2017年5月31日 下午1:37:50 + */ + public static String getLastDateOfThisMonth() { + SimpleDateFormat format = new SimpleDateFormat(ISO_EXPANDED_DATE_FORMAT); + + Calendar calendarLast = Calendar.getInstance(); + calendarLast.setTime(new Date()); + calendarLast.getActualMaximum(Calendar.DAY_OF_MONTH); + + String lastDate = format.format(calendarLast.getTime()); + return lastDate; + } + + /** + * @Description: 判断字符串日期是否匹配指定的格式化日期 + */ + public static boolean isValidDate(String strDate, String formatter) { + SimpleDateFormat sdf = null; + ParsePosition pos = new ParsePosition(0); + + if (StringUtils.isBlank(strDate) || StringUtils.isBlank(formatter)) { + return false; + } + try { + sdf = new SimpleDateFormat(formatter); + sdf.setLenient(false); + Date date = sdf.parse(strDate, pos); + if (date == null) { + return false; + } else { + if (pos.getIndex() > sdf.format(date).length()) { + return false; + } + return true; + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public static void main(String[] args) + { +// String timeDir=DateUtil.dateToString(new Date(),DateUtil.ISO_EXPANDED_DATE_FORMAT); +// System.out.println(timeDir); + boolean flag = DateUtil.isValidDate("1990-10-32", DateUtil.ISO_EXPANDED_DATE_FORMAT); + System.out.println(flag); + } + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DayCode.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DayCode.java new file mode 100644 index 000000000..59b892cc9 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DayCode.java @@ -0,0 +1,19 @@ +package com.wzj.soopin.content.utils; + + + +public class DayCode { + static RandomCodeStrategy strategy; + + static { + DayPrefixRandomCodeStrategy dayPrefixCodeStrategy = new DayPrefixRandomCodeStrategy("yyMM"); + dayPrefixCodeStrategy.setMinRandomSize(7); + dayPrefixCodeStrategy.setMaxRandomSize(7); + strategy = dayPrefixCodeStrategy; + strategy.init(); + } + + public static synchronized String next() { + return String.format("%d-%04d-%07d", Id.getWorkerId(), strategy.prefix(), strategy.next()); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DayPrefixRandomCodeStrategy.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DayPrefixRandomCodeStrategy.java new file mode 100644 index 000000000..9867626dd --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DayPrefixRandomCodeStrategy.java @@ -0,0 +1,41 @@ +package com.wzj.soopin.content.utils; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class DayPrefixRandomCodeStrategy extends DefaultRandomCodeStrategy { + private final String dayFormat; + private String lastDay; + + public DayPrefixRandomCodeStrategy(String dayFormat) { + this.dayFormat = dayFormat; + } + + @Override + public void init() { + String day = createDate(); + if (day.equals(lastDay)) + throw new RuntimeException("init failed for day unrolled"); + + lastDay = day; + + availableCodes.clear(); + release(); + + prefixIndex = Integer.parseInt(lastDay); + if (tryUsePrefix()) return; + + throw new RuntimeException("prefix is not available " + prefixIndex); + } + + private String createDate() { + return new SimpleDateFormat(dayFormat).format(new Date()); + } + + @Override + public int next() { + if (!lastDay.equals(createDate())) init(); + + return super.next(); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DefaultRandomCodeStrategy.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DefaultRandomCodeStrategy.java new file mode 100644 index 000000000..9310ad59f --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DefaultRandomCodeStrategy.java @@ -0,0 +1,196 @@ +package com.wzj.soopin.content.utils; + + +import com.wzj.soopin.content.idworker.utils.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.security.SecureRandom; +import java.util.ArrayDeque; +import java.util.BitSet; +import java.util.Queue; + +public class DefaultRandomCodeStrategy implements RandomCodeStrategy { + public static final int MAX_BITS = 1000000; + + Logger log = LoggerFactory.getLogger(DefaultRandomCodeStrategy.class); + + File idWorkerHome = Utils.createIdWorkerHome(); + volatile FileLock fileLock; + BitSet codesFilter; + + int prefixIndex = -1; + File codePrefixIndex; + + int minRandomSize = 6; + int maxRandomSize = 6; + + public DefaultRandomCodeStrategy() { + destroyFileLockWhenShutdown(); + } + + @Override + public void init() { + release(); + + while (++prefixIndex < 1000) { + if (tryUsePrefix()) return; + } + + throw new RuntimeException("all prefixes are used up, the world maybe ends!"); + } + + public DefaultRandomCodeStrategy setMinRandomSize(int minRandomSize) { + this.minRandomSize = minRandomSize; + return this; + } + + public DefaultRandomCodeStrategy setMaxRandomSize(int maxRandomSize) { + this.maxRandomSize = maxRandomSize; + return this; + } + + protected boolean tryUsePrefix() { + codePrefixIndex = new File(idWorkerHome, Id.getWorkerId() + ".code.prefix." + prefixIndex); + + if (!createPrefixIndexFile()) return false; + if (!createFileLock()) return false; + if (!createBloomFilter()) return false; + + log.info("get available prefix index file {}", codePrefixIndex); + + return true; + } + + private boolean createFileLock() { + if (fileLock != null) fileLock.destroy(); + fileLock = new FileLock(codePrefixIndex); + return fileLock.tryLock(); + } + + private boolean createBloomFilter() { + codesFilter = fileLock.readObject(); + if (codesFilter == null) { + log.info("create new bloom filter"); + codesFilter = new BitSet(MAX_BITS); // 2^24 + } else { + int size = codesFilter.cardinality(); + if (size >= MAX_BITS) { + log.warn("bloom filter with prefix file {} is already full", codePrefixIndex); + return false; + } + log.info("recreate bloom filter with cardinality {}", size); + } + + return true; + } + + private void destroyFileLockWhenShutdown() { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + release(); + } + }); + } + + private boolean createPrefixIndexFile() { + try { + codePrefixIndex.createNewFile(); + return codePrefixIndex.exists(); + } catch (IOException e) { + e.printStackTrace(); + log.warn("create file {} error {}", codePrefixIndex, e.getMessage()); + } + return false; + } + + @Override + public int prefix() { + return prefixIndex; + } + + static final int CACHE_CODES_NUM = 1000; + + SecureRandom secureRandom = new SecureRandom(); + Queue availableCodes = new ArrayDeque(CACHE_CODES_NUM); + + @Override + public int next() { + if (availableCodes.isEmpty()) generate(); + + return availableCodes.poll(); + } + + @Override + public synchronized void release() { + if (fileLock != null) { + fileLock.writeObject(codesFilter); + fileLock.destroy(); + fileLock = null; + } + } + + private void generate() { + for (int i = 0; i < CACHE_CODES_NUM; ++i) + availableCodes.add(generateOne()); + + fileLock.writeObject(codesFilter); + } + + private int generateOne() { + while (true) { + int code = secureRandom.nextInt(max(maxRandomSize)); + boolean existed = contains(code); + + code = !existed ? add(code) : tryFindAvailableCode(code); + if (code >= 0) return code; + + init(); + } + } + + private int tryFindAvailableCode(int code) { + int next = codesFilter.nextClearBit(code); + if (next != -1 && next < max(maxRandomSize)) return add(next); + + next = codesFilter.previousClearBit(code); + if (next != -1) return add(next); + + return -1; + } + + private int add(int code) { + codesFilter.set(code); + return code; + } + + private boolean contains(int code) { + return codesFilter.get(code); + } + + + private int max(int size) { + switch (size) { + case 1: // fall through + case 2: // fall through + case 3: // fall through + case 4: + return 10000; + case 5: + return 100000; + case 6: + return 1000000; + case 7: + return 10000000; + case 8: + return 100000000; + case 9: + return 1000000000; + default: + return Integer.MAX_VALUE; + } + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DefaultWorkerIdStrategy.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DefaultWorkerIdStrategy.java new file mode 100644 index 000000000..6e331ee91 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DefaultWorkerIdStrategy.java @@ -0,0 +1,205 @@ +package com.wzj.soopin.content.utils; + + +import com.wzj.soopin.content.idworker.utils.HttpReq; +import com.wzj.soopin.content.idworker.utils.Ip; +import com.wzj.soopin.content.idworker.utils.Props; +import com.wzj.soopin.content.idworker.utils.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.security.SecureRandom; +import java.util.Properties; +import java.util.Random; + +public class DefaultWorkerIdStrategy implements WorkerIdStrategy { + static long workerIdBits = 10L; + static long maxWorkerId = -1L ^ (-1L << workerIdBits); + static Random random = new SecureRandom(); + + public static final WorkerIdStrategy instance = new DefaultWorkerIdStrategy(); + + private final Properties props = + Props.tryProperties("idworker-client.properties", Utils.DOT_IDWORKERS); + private final String idWorkerServerUrl = + props.getProperty("server.address", "http://id.worker.server:18001"); + + String userName = System.getProperty("user.name"); + + String ipDotUsername = Ip.ip + "." + userName; + String ipudotlock = ipDotUsername + ".lock."; + int workerIdIndex = ipudotlock.length(); + long workerId; + FileLock fileLock; + + Logger logger = LoggerFactory.getLogger(DefaultWorkerIdStrategy.class); + private boolean inited; + + + private void init() { + workerId = findAvailWorkerId(); + if (workerId >= 0) { + destroyFileLockWhenShutdown(); + startSyncThread(); + } else { + syncWithWorkerIdServer(); + workerId = findAvailWorkerId(); + if (workerId < 0) workerId = increaseWithWorkerIdServer(); + } + + if (workerId < 0) workerId = tryToCreateOnIp(); + if (workerId < 0) { + logger.warn("DANGEROUS!!! Try to use random worker id."); + workerId = tryToRandomOnIp(); // Try avoiding! it could cause duplicated + } + + if (workerId < 0) { + logger.warn("the world may be ended!"); + throw new RuntimeException("the world may be ended"); + } + } + + private void destroyFileLockWhenShutdown() { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + fileLock.destroy(); + } + }); + } + + private void startSyncThread() { + new Thread() { + @Override + public void run() { + syncWithWorkerIdServer(); + } + }.start(); + } + + private long increaseWithWorkerIdServer() { + String incId = HttpReq.get(idWorkerServerUrl) + .req("/inc") + .param("ipu", ipDotUsername) + .exec(); + if (incId == null || incId.trim().isEmpty()) return -1L; + + long lid = Long.parseLong(incId); + + return checkAvail(lid); + } + + private long tryToCreateOnIp() { + long wid = Ip.lip & maxWorkerId; + + return checkAvail(wid); + } + + private long tryToRandomOnIp() { + long avaiWorkerId = -1L; + long tryTimes = -1; + + while (avaiWorkerId < 0 && ++tryTimes < maxWorkerId) { + long wid = Ip.lip & random.nextInt((int) maxWorkerId); + + avaiWorkerId = checkAvail(wid); + } + return avaiWorkerId; + } + + private long checkAvail(long wid) { + long availWorkerId = -1L; + try { + File idWorkerHome = Utils.createIdWorkerHome(); + new File(idWorkerHome, ipudotlock + String.format("%04d", wid)).createNewFile(); + availWorkerId = findAvailWorkerId(); + } catch (IOException e) { + logger.warn("checkAvail error", e); + } + + return availWorkerId; + } + + private void syncWithWorkerIdServer() { + String syncIds = HttpReq.get(idWorkerServerUrl).req("/sync") + .param("ipu", ipDotUsername).param("ids", buildWorkerIdsOfCurrentIp()) + .exec(); + if (syncIds == null || syncIds.trim().isEmpty()) return; + + String[] syncIdsArr = syncIds.split(","); + File idWorkerHome = Utils.createIdWorkerHome(); + for (String syncId : syncIdsArr) { + try { + new File(idWorkerHome, ipudotlock + syncId).createNewFile(); + } catch (IOException e) { + logger.warn("create workerid lock file error", e); + } + } + } + + private String buildWorkerIdsOfCurrentIp() { + StringBuilder sb = new StringBuilder(); + File idWorkerHome = Utils.createIdWorkerHome(); + for (File lockFile : idWorkerHome.listFiles()) { + // check the format like 10.142.1.151.lock.0001 + if (!lockFile.getName().startsWith(ipudotlock)) continue; + + String workerId = lockFile.getName().substring(workerIdIndex); + if (!workerId.matches("\\d\\d\\d\\d")) continue; + + if (sb.length() > 0) sb.append(','); + sb.append(workerId); + } + + return sb.toString(); + } + + + /** + * Find the local available worker id. + * + * @return -1 when N/A + */ + private long findAvailWorkerId() { + File idWorkerHome = Utils.createIdWorkerHome(); + + for (File lockFile : idWorkerHome.listFiles()) { + // check the format like 10.142.1.151.lock.0001 + if (!lockFile.getName().startsWith(ipudotlock)) continue; + + String workerId = lockFile.getName().substring(workerIdIndex); + if (!workerId.matches("\\d\\d\\d\\d")) continue; + + FileLock fileLock = new FileLock(lockFile); + if (!fileLock.tryLock()) { + fileLock.destroy(); + continue; + } + + this.fileLock = fileLock; + return Long.parseLong(workerId); + } + + return -1; + } + + @Override + public void initialize() { + if (inited) return; + init(); + this.inited = true; + } + + @Override + public long availableWorkerId() { + return workerId; + } + + @Override + public void release() { + if (fileLock != null) fileLock.destroy(); + inited = false; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DesensitizationUtil.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DesensitizationUtil.java new file mode 100644 index 000000000..468096238 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/DesensitizationUtil.java @@ -0,0 +1,77 @@ +package com.wzj.soopin.content.utils; + +/** + * 通用脱敏工具类 + * 可用于: + * 用户名 + * 手机号 + * 邮箱 + * 地址等 + */ +public class DesensitizationUtil { + + private static final int SIZE = 6; + private static final String SYMBOL = "*"; + + public static void main(String[] args) { + String name = commonDisplay("慕课网"); + String mobile = commonDisplay("13900000000"); + String mail = commonDisplay("admin@imooc.com"); + String address = commonDisplay("北京大运河东路888号"); + + System.out.println(name); + System.out.println(mobile); + System.out.println(mail); + System.out.println(address); + } + + /** + * 通用脱敏方法 + * @param value + * @return + */ + public static String commonDisplay(String value) { + if (null == value || "".equals(value)) { + return value; + } + int len = value.length(); + int pamaone = len / 2; + int pamatwo = pamaone - 1; + int pamathree = len % 2; + StringBuilder stringBuilder = new StringBuilder(); + if (len <= 2) { + if (pamathree == 1) { + return SYMBOL; + } + stringBuilder.append(SYMBOL); + stringBuilder.append(value.charAt(len - 1)); + } else { + if (pamatwo <= 0) { + stringBuilder.append(value.substring(0, 1)); + stringBuilder.append(SYMBOL); + stringBuilder.append(value.substring(len - 1, len)); + + } else if (pamatwo >= SIZE / 2 && SIZE + 1 != len) { + int pamafive = (len - SIZE) / 2; + stringBuilder.append(value.substring(0, pamafive)); + for (int i = 0; i < SIZE; i++) { + stringBuilder.append(SYMBOL); + } + if ((pamathree == 0 && SIZE / 2 == 0) || (pamathree != 0 && SIZE % 2 != 0)) { + stringBuilder.append(value.substring(len - pamafive, len)); + } else { + stringBuilder.append(value.substring(len - (pamafive + 1), len)); + } + } else { + int pamafour = len - 2; + stringBuilder.append(value.substring(0, 1)); + for (int i = 0; i < pamafour; i++) { + stringBuilder.append(SYMBOL); + } + stringBuilder.append(value.substring(len - 1, len)); + } + } + return stringBuilder.toString(); + } + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/FileLock.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/FileLock.java new file mode 100644 index 000000000..f7066080b --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/FileLock.java @@ -0,0 +1,132 @@ +package com.wzj.soopin.content.utils; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.nio.channels.Channels; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.FileChannel; +import java.nio.channels.OverlappingFileLockException; + +/** + * A file lock a la flock/funlock + *

+ * The given path will be created and opened if it doesn't exist. + */ +public class FileLock { + private final File file; + private FileChannel channel; + private java.nio.channels.FileLock flock = null; + Logger logger = LoggerFactory.getLogger(FileLock.class); + + public FileLock(File file) { + this.file = file; + + try { + file.createNewFile(); // create the file if it doesn't exist + channel = new RandomAccessFile(file, "rw").getChannel(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + /** + * Lock the file or throw an exception if the lock is already held + */ + public void lock() { + try { + synchronized (this) { + logger.trace("Acquiring lock on {}", file.getAbsolutePath()); + flock = channel.lock(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Try to lock the file and return true if the locking succeeds + */ + public boolean tryLock() { + synchronized (this) { + logger.trace("Acquiring lock on {}", file.getAbsolutePath()); + try { + // weirdly this method will return null if the lock is held by another + // process, but will throw an exception if the lock is held by this process + // so we have to handle both cases + flock = channel.tryLock(); + return flock != null; + } catch (OverlappingFileLockException e) { + return false; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + /** + * Unlock the lock if it is held + */ + public void unlock() { + synchronized (this) { + logger.trace("Releasing lock on {}", file.getAbsolutePath()); + if (flock == null) return; + try { + flock.release(); + } catch (ClosedChannelException e) { + // Ignore + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + /** + * Destroy this lock, closing the associated FileChannel + */ + public void destroy() { + synchronized (this) { + unlock(); + if (!channel.isOpen()) return; + + try { + channel.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + + @SuppressWarnings("unchecked") + public T readObject() { + try { + InputStream is = Channels.newInputStream(channel); + ObjectInputStream objectReader = new ObjectInputStream(is); + return (T) objectReader.readObject(); + } catch (EOFException e) { + } catch (Exception e) { + throw new RuntimeException(e); + } + + return null; + } + + + public synchronized boolean writeObject(Object object) { + if (!channel.isOpen()) return false; + + try { + channel.position(0); + OutputStream out = Channels.newOutputStream(channel); + ObjectOutputStream objectOutput = new ObjectOutputStream(out); + objectOutput.writeObject(object); + return true; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/GsonUtil.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/GsonUtil.java new file mode 100644 index 000000000..416dd77d2 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/GsonUtil.java @@ -0,0 +1,24 @@ +package com.wzj.soopin.content.utils; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class GsonUtil { + + private static Gson gson = null; + + private GsonUtil() { + } + + static { + gson = new GsonBuilder().create(); + } + + public static String beanToJson(Object value) { + return gson.toJson(value); + } + + public static T jsonToBean(String content, Class valueType) { + return gson.fromJson(content, valueType); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/IPUtil.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/IPUtil.java new file mode 100644 index 000000000..bb967961a --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/IPUtil.java @@ -0,0 +1,38 @@ +package com.wzj.soopin.content.utils; + + +import jakarta.servlet.http.HttpServletRequest; + +/** + * 用户获得用户ip的工具类 + */ +public class IPUtil { + + /** + * 获取请求IP: + * 用户的真实IP不能使用request.getRemoteAddr() + * 这是因为可能会使用一些代理软件,这样ip获取就不准确了 + * 此外我们如果使用了多级(LVS/Nginx)反向代理的话,ip需要从X-Forwarded-For中获得第一个非unknown的IP才是用户的有效ip。 + * @param request + * @return + */ + public static String getRequestIp(HttpServletRequest request) { + String ip = request.getHeader("x-forwarded-for"); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + return ip; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/Id.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/Id.java new file mode 100644 index 000000000..1fad2bcf1 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/Id.java @@ -0,0 +1,29 @@ +package com.wzj.soopin.content.utils; + + + +public class Id { + private static WorkerIdStrategy workerIdStrategy; + private static IdWorker idWorker; + + static { + configure(DefaultWorkerIdStrategy.instance); + } + + public static synchronized void configure(WorkerIdStrategy custom) { + if (workerIdStrategy == custom) return; + + if (workerIdStrategy != null) workerIdStrategy.release(); + workerIdStrategy = custom; + workerIdStrategy.initialize(); + idWorker = new IdWorker(workerIdStrategy.availableWorkerId()); + } + + public static long next() { + return idWorker.nextId(); + } + + public static long getWorkerId() { + return idWorker.getWorkerId(); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/IdWorker.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/IdWorker.java new file mode 100644 index 000000000..c22aaea60 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/IdWorker.java @@ -0,0 +1,91 @@ +package com.wzj.soopin.content.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.SecureRandom; + +public class IdWorker { + protected long epoch = 1288834974657L; +// protected long epoch = 1387886498127L; // 2013-12-24 20:01:38.127 + + + protected long workerIdBits = 10L; + protected long maxWorkerId = -1L ^ (-1L << workerIdBits); + protected long sequenceBits = 11L; + + protected long workerIdShift = sequenceBits; + protected long timestampLeftShift = sequenceBits + workerIdBits; + protected long sequenceMask = -1L ^ (-1L << sequenceBits); + + protected long lastMillis = -1L; + + protected final long workerId; + protected long sequence = 0L; + protected Logger logger = LoggerFactory.getLogger(IdWorker.class); + + public IdWorker(long workerId) { + this.workerId = checkWorkerId(workerId); + + logger.debug("worker starting. timestamp left shift {}, worker id {}", timestampLeftShift, workerId); + } + + public long getEpoch() { + return epoch; + } + + private long checkWorkerId(long workerId) { + // sanity check for workerId + if (workerId > maxWorkerId || workerId < 0) { + int rand = new SecureRandom().nextInt((int) maxWorkerId + 1); + logger.warn("worker Id can't be greater than {} or less than 0, use a random {}", maxWorkerId, rand); + return rand; + } + + return workerId; + } + + public synchronized long nextId() { + long timestamp = millisGen(); + + if (timestamp < lastMillis) { + logger.error("clock is moving backwards. Rejecting requests until {}.", lastMillis); + throw new InvalidSystemClock(String.format( + "Clock moved backwards. Refusing to generate id for {} milliseconds", lastMillis - timestamp)); + } + + if (lastMillis == timestamp) { + sequence = (sequence + 1) & sequenceMask; + if (sequence == 0) + timestamp = tilNextMillis(lastMillis); + } else { + sequence = 0; + } + + lastMillis = timestamp; + long diff = timestamp - getEpoch(); + return (diff << timestampLeftShift) | + (workerId << workerIdShift) | + sequence; + } + + protected long tilNextMillis(long lastMillis) { + long millis = millisGen(); + while (millis <= lastMillis) + millis = millisGen(); + + return millis; + } + + protected long millisGen() { + return System.currentTimeMillis(); + } + + public long getLastMillis() { + return lastMillis; + } + + public long getWorkerId() { + return workerId; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/InvalidSystemClock.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/InvalidSystemClock.java new file mode 100644 index 000000000..e93df8d95 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/InvalidSystemClock.java @@ -0,0 +1,7 @@ +package com.wzj.soopin.content.utils; + +public class InvalidSystemClock extends RuntimeException { + public InvalidSystemClock(String message) { + super(message); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/JsonUtils.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/JsonUtils.java new file mode 100644 index 000000000..0019482a6 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/JsonUtils.java @@ -0,0 +1,74 @@ +package com.wzj.soopin.content.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.List; + +/** + * + * @Title: JsonUtils.java + * @Package com.imooc.utils + * @Description: json转换类 + * Copyright: Copyright (c) + * Company: www.imooc.com + * + * @author imooc + */ +public class JsonUtils { + + // 定义jackson对象 + private static final ObjectMapper MAPPER = new ObjectMapper(); + + /** + * 将对象转换成json字符串。 + * @param data + * @return + */ + public static String objectToJson(Object data) { + try { + String string = MAPPER.writeValueAsString(data); + return string; + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 将json结果集转化为对象 + * + * @param jsonData json数据 + * @param beanType 对象中的object类型 + * @return + */ + public static T jsonToPojo(String jsonData, Class beanType) { + try { + T t = MAPPER.readValue(jsonData, beanType); + return t; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 将json数据转换成pojo对象list + * @param jsonData + * @param beanType + * @return + */ + public static List jsonToList(String jsonData, Class beanType) { + JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType); + try { + List list = MAPPER.readValue(jsonData, javaType); + return list; + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/MyInfo.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/MyInfo.java new file mode 100644 index 000000000..2d6d5d0ba --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/MyInfo.java @@ -0,0 +1,9 @@ +package com.wzj.soopin.content.utils; + +public class MyInfo { + + public static String getMobile() { + return ""; + } + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/PagedGridResult.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/PagedGridResult.java new file mode 100644 index 000000000..782ccc962 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/PagedGridResult.java @@ -0,0 +1,49 @@ +package com.wzj.soopin.content.utils; + +import java.util.List; + +/** + * + * @Title: PagedGridResult.java + * @Package com.imooc.utils + * @Description: 用来返回分页Grid的数据格式 + * Copyright: Copyright (c) 2021 + */ +public class PagedGridResult { + + private int page; // 当前页数 + private long total; // 总页数 + private long records; // 总记录数 + private List rows; // 每行显示的内容 + + public int getPage() { + return page; + } + public void setPage(int page) { + this.page = page; + } + + public long getTotal() { + return total; + } + + public void setTotal(long total) { + this.total = total; + } + + public void setTotal(int total) { + this.total = total; + } + public long getRecords() { + return records; + } + public void setRecords(long records) { + this.records = records; + } + public List getRows() { + return rows; + } + public void setRows(List rows) { + this.rows = rows; + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/RandomCodeStrategy.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/RandomCodeStrategy.java new file mode 100644 index 000000000..c79313596 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/RandomCodeStrategy.java @@ -0,0 +1,11 @@ +package com.wzj.soopin.content.utils; + +public interface RandomCodeStrategy { + void init(); + + int prefix(); + + int next(); + + void release(); +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/RedisOperator.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/RedisOperator.java new file mode 100644 index 000000000..20ed89ff0 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/RedisOperator.java @@ -0,0 +1,309 @@ +package com.wzj.soopin.content.utils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.StringRedisConnection; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * @Title: Redis 工具类 + * @author 风间影月 + */ +@Component +public class RedisOperator { + + @Autowired + private StringRedisTemplate redisTemplate; + + // Key(键),简单的key-value操作 + + /** + * 判断key是否存在 + * @param key + * @return + */ + public boolean keyIsExist(String key) { + return redisTemplate.hasKey(key); + } + + /** + * 实现命令:TTL key,以秒为单位,返回给定 key的剩余生存时间(TTL, time to live)。 + * + * @param key + * @return + */ + public long ttl(String key) { + return redisTemplate.getExpire(key); + } + + /** + * 实现命令:expire 设置过期时间,单位秒 + * + * @param key + * @return + */ + public void expire(String key, long timeout) { + redisTemplate.expire(key, timeout, TimeUnit.SECONDS); + } + + /** + * 实现命令:increment key,增加key一次 + * + * @param key + * @return + */ + public long increment(String key, long delta) { + return redisTemplate.opsForValue().increment(key, delta); + } + + /** + * 累加,使用hash + */ + public long incrementHash(String name, String key, long delta) { + return redisTemplate.opsForHash().increment(name, key, delta); + } + + /** + * 累减,使用hash + */ + public long decrementHash(String name, String key, long delta) { + delta = delta * (-1); + return redisTemplate.opsForHash().increment(name, key, delta); + } + + /** + * hash 设置value + */ + public void setHashValue(String name, String key, String value) { + redisTemplate.opsForHash().put(name, key, value); + } + + /** + * hash 获得value + */ + public String getHashValue(String name, String key) { + return (String)redisTemplate.opsForHash().get(name, key); + } + + /** + * 实现命令:decrement key,减少key一次 + * + * @param key + * @return + */ + public long decrement(String key, long delta) { + return redisTemplate.opsForValue().decrement(key, delta); + } + + /** + * 实现命令:KEYS pattern,查找所有符合给定模式 pattern的 key + */ + public Set keys(String pattern) { + return redisTemplate.keys(pattern); + } + + /** + * 实现命令:DEL key,删除一个key + * + * @param key + */ + public void del(String key) { + redisTemplate.delete(key); + } + + // String(字符串) + + /** + * 实现命令:SET key value,设置一个key-value(将字符串值 value关联到 key) + * + * @param key + * @param value + */ + public void set(String key, String value) { + redisTemplate.opsForValue().set(key, value); + } + + /** + * 实现命令:SET key value EX seconds,设置key-value和超时时间(秒) + * + * @param key + * @param value + * @param timeout + * (以秒为单位) + */ + public void set(String key, String value, long timeout) { + redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS); + } + + /** + * 如果key不存在,则设置,如果存在,则报错 + * @param key + * @param value + */ + public void setnx60s(String key, String value) { + redisTemplate.opsForValue().setIfAbsent(key, value, 60, TimeUnit.SECONDS); + } + + /** + * 如果key不存在,则设置,如果存在,则报错 + * @param key + * @param value + */ + public void setnx(String key, String value) { + redisTemplate.opsForValue().setIfAbsent(key, value); + } + + /** + * 实现命令:GET key,返回 key所关联的字符串值。 + * + * @param key + * @return value + */ + public String get(String key) { + return (String)redisTemplate.opsForValue().get(key); + } + + /** + * 批量查询,对应mget + * @param keys + * @return + */ + public List mget(List keys) { + return redisTemplate.opsForValue().multiGet(keys); + } + + /** + * 批量查询,管道pipeline + * @param keys + * @return + */ + public List batchGet(List keys) { + +// nginx -> keepalive +// redis -> pipeline + + List result = redisTemplate.executePipelined(new RedisCallback() { + @Override + public String doInRedis(RedisConnection connection) throws DataAccessException { + StringRedisConnection src = (StringRedisConnection)connection; + + for (String k : keys) { + src.get(k); + } + return null; + } + }); + + return result; + } + + + // Hash(哈希表) + + /** + * 实现命令:HSET key field value,将哈希表 key中的域 field的值设为 value + * + * @param key + * @param field + * @param value + */ + public void hset(String key, String field, Object value) { + redisTemplate.opsForHash().put(key, field, value); + } + + /** + * 实现命令:HGET key field,返回哈希表 key中给定域 field的值 + * + * @param key + * @param field + * @return + */ + public String hget(String key, String field) { + return (String) redisTemplate.opsForHash().get(key, field); + } + + /** + * 实现命令:HDEL key field [field ...],删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。 + * + * @param key + * @param fields + */ + public void hdel(String key, Object... fields) { + redisTemplate.opsForHash().delete(key, fields); + } + + /** + * 实现命令:HGETALL key,返回哈希表 key中,所有的域和值。 + * + * @param key + * @return + */ + public Map hgetall(String key) { + return redisTemplate.opsForHash().entries(key); + } + + // List(列表) + + /** + * 实现命令:LPUSH key value,将一个值 value插入到列表 key的表头 + * + * @param key + * @param value + * @return 执行 LPUSH命令后,列表的长度。 + */ + public long lpush(String key, String value) { + return redisTemplate.opsForList().leftPush(key, value); + } + + /** + * 实现命令:LPOP key,移除并返回列表 key的头元素。 + * + * @param key + * @return 列表key的头元素。 + */ + public String lpop(String key) { + return (String)redisTemplate.opsForList().leftPop(key); + } + + /** + * 实现命令:RPUSH key value,将一个值 value插入到列表 key的表尾(最右边)。 + * + * @param key + * @param value + * @return 执行 LPUSH命令后,列表的长度。 + */ + public long rpush(String key, String value) { + return redisTemplate.opsForList().rightPush(key, value); + } + // List(列表) + /** + * 实现命令:LRANGE key start stop,返回列表key中指定区间内的元素 + * + * @param key Redis key + * @param start 开始索引 + * @param stop 结束索引 + * @return 返回指定区间的元素 + */ + public List lrange(String key, long start, long stop) { + return redisTemplate.opsForList().range(key, start, stop); + } + /** + * 实现命令:LREM key count value,移除列表中与 value 相等的元素 + * + * @param key Redis key + * @param count 删除的数量(正数表示从头部开始删除,负数从尾部,0表示删除全部匹配项) + * @param value 要删除的元素值 + * @return 被删除的元素个数 + */ + public Long lrem(String key, long count, Object value) { + return redisTemplate.opsForList().remove(key, count, value); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/SMSUtils.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/SMSUtils.java new file mode 100644 index 000000000..632bd9736 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/SMSUtils.java @@ -0,0 +1,74 @@ +package com.wzj.soopin.content.utils; + +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.sms.v20210111.SmsClient; +import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest; +import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class SMSUtils { + @Autowired + private TencentCloudProperties tencentCloudProperties; + + public void sendSMS(String phone, String code) throws Exception { + try { + /* 必要步骤: + * 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。 + * 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。 + * 你也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人, + * 以免泄露密钥对危及你的财产安全。 + * CAM密匙查询获取: https://console.cloud.tencent.com/cam/capi*/ + Credential cred = new Credential(tencentCloudProperties.getSecretId(), + tencentCloudProperties.getSecretKey()); + + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + +// httpProfile.setReqMethod("POST"); // 默认使用POST + + /* SDK会自动指定域名。通常是不需要特地指定域名的,但是如果你访问的是金融区的服务 + * 则必须手动指定域名,例如sms的上海金融区域名: sms.ap-shanghai-fsi.tencentcloudapi.com */ + httpProfile.setEndpoint("sms.tencentcloudapi.com"); + + // 实例化一个client选项 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + // 实例化要请求产品的client对象,clientProfile是可选的 + SmsClient client = new SmsClient(cred, "ap-nanjing", clientProfile); + + // 实例化一个请求对象,每个接口都会对应一个request对象 + SendSmsRequest req = new SendSmsRequest(); + String[] phoneNumberSet1 = {"+86" + phone};//电话号码 + req.setPhoneNumberSet(phoneNumberSet1); + req.setSmsSdkAppId("1400966042"); // 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId + req.setSignName("无终街科技"); // 签名 + req.setTemplateId("2375314"); // 模板id:必须填写已审核通过的模板 ID。模板ID可登录 [短信控制台] 查看 + + /* 模板参数(自定义占位变量): 若无模板参数,则设置为空 */ + String[] templateParamSet1 = {code}; + req.setTemplateParamSet(templateParamSet1); + + // 返回的resp是一个SendSmsResponse的实例,与请求对象对应 + SendSmsResponse resp = client.SendSms(req); + // 输出json格式的字符串回包 +// System.out.println(SendSmsResponse.toJsonString(resp)); + } catch (TencentCloudSDKException e) { + System.out.println(e.toString()); + } + } + + public static void main(String[] args) { + try { + new SMSUtils().sendSMS("15237439161", "7896"); + } catch (Exception e) { + e.printStackTrace(); + } + } +} + + diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/Sid.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/Sid.java new file mode 100644 index 000000000..4774f1eba --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/Sid.java @@ -0,0 +1,63 @@ +package com.wzj.soopin.content.utils; + +import com.wzj.soopin.content.idworker.utils.Utils; +import org.springframework.stereotype.Component; + +import java.text.SimpleDateFormat; +import java.util.Date; + +@Component +public class Sid { + private static WorkerIdStrategy workerIdStrategy; + private static IdWorker idWorker; + + static { + configure(DefaultWorkerIdStrategy.instance); + } + + + public static synchronized void configure(WorkerIdStrategy custom) { + if (workerIdStrategy != null) { + workerIdStrategy.release(); + } + workerIdStrategy = custom; + idWorker = new IdWorker(workerIdStrategy.availableWorkerId()) { + @Override + public long getEpoch() { + return Utils.midnightMillis(); + } + }; + } + + /** + * 一天最大毫秒86400000,最大占用27比特 + * 27+10+11=48位 最大值281474976710655(15字),YK0XXHZ827(10字) + * 6位(YYMMDD)+15位,共21位 + * + * @return 固定21位数字字符串 + */ + + public static String next() { + long id = idWorker.nextId(); + String yyMMdd = new SimpleDateFormat("yyMMdd").format(new Date()); + return yyMMdd + String.format("%014d", id); + } + + + /** + * 返回固定16位的字母数字混编的字符串。 + */ + public String nextShort() { + long id = idWorker.nextId(); + String yyMMdd = new SimpleDateFormat("yyMMdd").format(new Date()); + return yyMMdd + Utils.padLeft(Utils.encode(id), 10, '0'); + } + + public static void main(String[] args) { + String aa = new Sid().nextShort(); + String bb = new Sid().next(); + + System.out.println(aa); + System.out.println(bb); + } +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/TencentCloudProperties.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/TencentCloudProperties.java new file mode 100644 index 000000000..b8588632a --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/TencentCloudProperties.java @@ -0,0 +1,23 @@ +package com.wzj.soopin.content.utils; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +/** + * @author vercen + * @version 1.0 + * @date 2023/5/25 10:21 + * 获取短信配置 + */ +@Component +@Data +@PropertySource("classpath:tencentcloud.properties") +@ConfigurationProperties(prefix = "tencent.cloud") +public class TencentCloudProperties { + + private String secretId; + private String secretKey; + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/Test.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/Test.java new file mode 100644 index 000000000..160fb2de6 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/Test.java @@ -0,0 +1,12 @@ +package com.wzj.soopin.content.utils; + +public class Test { + + public static void main(String[] args) { + + for (int i = 0 ; i < 1000 ; i ++) { +// System.out.println(Sid.nextShort()); + } + } + +} diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/WorkerIdStrategy.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/WorkerIdStrategy.java new file mode 100644 index 000000000..4e089b1f2 --- /dev/null +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/utils/WorkerIdStrategy.java @@ -0,0 +1,9 @@ +package com.wzj.soopin.content.utils; + +public interface WorkerIdStrategy { + void initialize(); + + long availableWorkerId(); + + void release(); +}