修改vlog

This commit is contained in:
cjh 2025-05-30 10:53:21 +08:00
parent 81e5b80f64
commit 3bc7d53106
77 changed files with 4777 additions and 95 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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 {

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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: * # 分别代表什么意思
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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; // 消息创建时间
}

View File

@ -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;
}
}

View File

@ -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字段中
* 501bean验证错误不管多少个错误都以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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,7 @@
package com.wzj.soopin.content.idworker;
public class InvalidSystemClock extends RuntimeException {
public InvalidSystemClock(String message) {
super(message);
}
}

View File

@ -0,0 +1,11 @@
package com.wzj.soopin.content.idworker;
public interface RandomCodeStrategy {
void init();
int prefix();
int next();
void release();
}

View File

@ -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);
}
}

View File

@ -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());
}
}
}

View File

@ -0,0 +1,9 @@
package com.wzj.soopin.content.idworker;
public interface WorkerIdStrategy {
void initialize();
long availableWorkerId();
void release();
}

View File

@ -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();
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1 @@
package com.wzj.soopin.content.idworker.utils;

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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
}
}
}

View File

@ -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");
}
}

View File

@ -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;
}
}

View File

@ -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字段中
* 501bean验证错误不管多少个错误都以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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
/**

View File

@ -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 {
/**

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,7 @@
package com.wzj.soopin.content.utils;
public class InvalidSystemClock extends RuntimeException {
public InvalidSystemClock(String message) {
super(message);
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,9 @@
package com.wzj.soopin.content.utils;
public class MyInfo {
public static String getMobile() {
return "";
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,11 @@
package com.wzj.soopin.content.utils;
public interface RandomCodeStrategy {
void init();
int prefix();
int next();
void release();
}

View File

@ -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);
}
}

View File

@ -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 {
/* 必要步骤
* 实例化一个认证对象入参需要传入腾讯云账户密钥对secretIdsecretKey
* 这里采用的是从环境变量读取的方式需要在环境变量中先设置这两个值
* 你也可以直接在代码中写死密钥对但是小心不要将代码复制上传或者分享给他人
* 以免泄露密钥对危及你的财产安全
* 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();
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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());
}
}
}

View File

@ -0,0 +1,9 @@
package com.wzj.soopin.content.utils;
public interface WorkerIdStrategy {
void initialize();
long availableWorkerId();
void release();
}