修改vlog
This commit is contained in:
parent
81e5b80f64
commit
3bc7d53106
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -14,6 +14,23 @@
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
<!--腾讯云短信-->
|
||||
<dependency>
|
||||
<groupId>com.tencentcloudapi</groupId>
|
||||
<artifactId>tencentcloud-sdk-java</artifactId>
|
||||
<version>3.1.270</version>
|
||||
</dependency>
|
||||
|
||||
<!--腾讯云点播-->
|
||||
<dependency>
|
||||
<groupId>com.qcloud</groupId>
|
||||
<artifactId>vod_api</artifactId>
|
||||
<version>2.1.5</version>
|
||||
</dependency>
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
@ -97,6 +114,17 @@
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-sse</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper</artifactId>
|
||||
<version>5.3.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.12.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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: * 和 # 分别代表什么意思?
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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<String, String> 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<String, String> getErrors(BindingResult result) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
List<FieldError> errorList = result.getFieldErrors();
|
||||
for (FieldError ff : errorList) {
|
||||
// 错误所对应的属性字段名
|
||||
String field = ff.getField();
|
||||
// 错误的信息
|
||||
String msg = ff.getDefaultMessage();
|
||||
map.put(field, msg);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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; // 消息创建时间
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.wzj.soopin.content.idworker;
|
||||
|
||||
public class InvalidSystemClock extends RuntimeException {
|
||||
public InvalidSystemClock(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.wzj.soopin.content.idworker;
|
||||
|
||||
public interface RandomCodeStrategy {
|
||||
void init();
|
||||
|
||||
int prefix();
|
||||
|
||||
int next();
|
||||
|
||||
void release();
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.wzj.soopin.content.idworker;
|
||||
|
||||
public interface WorkerIdStrategy {
|
||||
void initialize();
|
||||
|
||||
long availableWorkerId();
|
||||
|
||||
void release();
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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<Integer> availableCodes = new ArrayDeque<Integer>(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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
* <p/>
|
||||
* 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> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
package com.wzj.soopin.content.idworker.utils;
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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 <T> List<T> readObjects(File file) {
|
||||
ArrayList<T> objects = new ArrayList<T>();
|
||||
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> 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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -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 {
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
||||
* <a href="http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html">Julian Day Calculations
|
||||
* (Gregorian Calendar)</a>, 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
|
||||
* <a href="http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html">Julian Day Calculations
|
||||
* (Gregorian Calendar)</a>, 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);
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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<Integer> availableCodes = new ArrayDeque<Integer>(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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
* <p/>
|
||||
* 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> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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> T jsonToBean(String content, Class<T> valueType) {
|
||||
return gson.fromJson(content, valueType);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.wzj.soopin.content.utils;
|
||||
|
||||
public class InvalidSystemClock extends RuntimeException {
|
||||
public InvalidSystemClock(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -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> T jsonToPojo(String jsonData, Class<T> 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 <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
|
||||
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
|
||||
try {
|
||||
List<T> list = MAPPER.readValue(jsonData, javaType);
|
||||
return list;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.wzj.soopin.content.utils;
|
||||
|
||||
public class MyInfo {
|
||||
|
||||
public static String getMobile() {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.wzj.soopin.content.utils;
|
||||
|
||||
public interface RandomCodeStrategy {
|
||||
void init();
|
||||
|
||||
int prefix();
|
||||
|
||||
int next();
|
||||
|
||||
void release();
|
||||
}
|
@ -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<String> 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<String> mget(List<String> keys) {
|
||||
return redisTemplate.opsForValue().multiGet(keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量查询,管道pipeline
|
||||
* @param keys
|
||||
* @return
|
||||
*/
|
||||
public List<Object> batchGet(List<String> keys) {
|
||||
|
||||
// nginx -> keepalive
|
||||
// redis -> pipeline
|
||||
|
||||
List<Object> result = redisTemplate.executePipelined(new RedisCallback<String>() {
|
||||
@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<Object, Object> 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<String> 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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.wzj.soopin.content.utils;
|
||||
|
||||
public interface WorkerIdStrategy {
|
||||
void initialize();
|
||||
|
||||
long availableWorkerId();
|
||||
|
||||
void release();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user