master
toesbieya 6 years ago
parent 6c7599acfc
commit 1c25927a1f
  1. 6
      java/cloud/.gitignore
  2. 20
      java/cloud/api/pom.xml
  3. 20
      java/cloud/api/src/main/java/cn/toesbieya/jxc/api/service/RecordApi.java
  4. 18
      java/cloud/api/src/main/java/cn/toesbieya/jxc/api/service/StockApi.java
  5. 11
      java/cloud/api/src/main/java/cn/toesbieya/jxc/api/service/system/ResourceApi.java
  6. 7
      java/cloud/api/src/main/java/cn/toesbieya/jxc/api/service/system/RoleApi.java
  7. 18
      java/cloud/api/src/main/java/cn/toesbieya/jxc/api/vo/AttachmentOperation.java
  8. 45
      java/cloud/common/pom.xml
  9. 19
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/config/FastJsonConfigFactory.java
  10. 34
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/config/RedisConfig.java
  11. 12
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/constant/DocumentConstant.java
  12. 18
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/constant/SessionConstant.java
  13. 23
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/constant/SocketConstant.java
  14. 15
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/enumeration/GeneralStatusEnum.java
  15. 7
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/exception/JsonResultException.java
  16. 33
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/BizDoc.java
  17. 25
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/BizDocHistory.java
  18. 16
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/BizDocSub.java
  19. 19
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/BizPurchaseInbound.java
  20. 12
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/BizPurchaseInboundSub.java
  21. 29
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/BizPurchaseOrder.java
  22. 15
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/BizPurchaseOrderSub.java
  23. 29
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/BizSellOrder.java
  24. 15
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/BizSellOrderSub.java
  25. 19
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/BizSellOutbound.java
  26. 12
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/BizSellOutboundSub.java
  27. 25
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/BizStock.java
  28. 26
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/Msg.java
  29. 14
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/MsgState.java
  30. 23
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/RecAttachment.java
  31. 23
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/RecLoginHistory.java
  32. 25
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/RecUserAction.java
  33. 14
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/StatFinishOrder.java
  34. 13
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/StatProfitGoods.java
  35. 16
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/StatProfitTotal.java
  36. 15
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/SysCategory.java
  37. 19
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/SysCustomer.java
  38. 14
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/SysDepartment.java
  39. 15
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/SysRegion.java
  40. 17
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/SysResource.java
  41. 17
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/SysRole.java
  42. 19
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/SysSupplier.java
  43. 22
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/entity/SysUser.java
  44. 9
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/vo/BaseSearch.java
  45. 23
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/vo/ResourceVo.java
  46. 83
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/vo/Result.java
  47. 21
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/vo/SocketEventVo.java
  48. 16
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/vo/SocketOfflineVo.java
  49. 17
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/vo/StockOutboundVo.java
  50. 20
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/vo/StockSearch.java
  51. 15
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/vo/StockSearchResult.java
  52. 31
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/model/vo/UserVo.java
  53. 53
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/utils/DateUtil.java
  54. 176
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/utils/RedisUtil.java
  55. 57
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/utils/SessionUtil.java
  56. 29
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/utils/SpringUtil.java
  57. 72
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/utils/Util.java
  58. 36
      java/cloud/common/src/main/java/cn/toesbieya/jxc/common/utils/WebSocketUtil.java
  59. 0
      java/cloud/common/src/main/resources/script/increase_and_expire.lua
  60. 45
      java/cloud/gateway/pom.xml
  61. 13
      java/cloud/gateway/src/main/java/cn/toesbieya/jxc/gateway/GatewayApplication.java
  62. 19
      java/cloud/gateway/src/main/java/cn/toesbieya/jxc/gateway/config/GatewayConfig.java
  63. 14
      java/cloud/gateway/src/main/java/cn/toesbieya/jxc/gateway/config/RateConfig.java
  64. 97
      java/cloud/gateway/src/main/java/cn/toesbieya/jxc/gateway/config/ResourceConfig.java
  65. 138
      java/cloud/gateway/src/main/java/cn/toesbieya/jxc/gateway/config/RouteConfig.java
  66. 13
      java/cloud/gateway/src/main/java/cn/toesbieya/jxc/gateway/controller/FallbackController.java
  67. 106
      java/cloud/gateway/src/main/java/cn/toesbieya/jxc/gateway/filter/SecurityFilter.java
  68. 68
      java/cloud/gateway/src/main/java/cn/toesbieya/jxc/gateway/filter/SentinelFilter.java
  69. 15
      java/cloud/gateway/src/main/resources/bootstrap.yml
  70. 25
      java/cloud/nacos-config/jxc-common-database.yml
  71. 8
      java/cloud/nacos-config/jxc-common-qiniu.yml
  72. 11
      java/cloud/nacos-config/jxc-common-redis.yml
  73. 60
      java/cloud/nacos-config/jxc-gateway.yml
  74. 2
      java/cloud/nacos-config/jxc-web-account.yml
  75. 4
      java/cloud/nacos-config/jxc-web-document.yml
  76. 4
      java/cloud/nacos-config/jxc-web-message.yml
  77. 2
      java/cloud/nacos-config/jxc-web-record.yml
  78. 2
      java/cloud/nacos-config/jxc-web-statistic.yml
  79. 2
      java/cloud/nacos-config/jxc-web-stock.yml
  80. 4
      java/cloud/nacos-config/jxc-web-system.yml
  81. 6
      java/cloud/nacos-config/jxc-websocket.yml
  82. 158
      java/cloud/pom.xml
  83. 35
      java/cloud/schedule/pom.xml
  84. 16
      java/cloud/schedule/src/main/java/cn/toesbieya/jxc/schedule/ScheduleApplication.java
  85. 45
      java/cloud/schedule/src/main/java/cn/toesbieya/jxc/schedule/config/ExecutorConfig.java
  86. 33
      java/cloud/schedule/src/main/java/cn/toesbieya/jxc/schedule/mapper/StatisticMapper.java
  87. 106
      java/cloud/schedule/src/main/java/cn/toesbieya/jxc/schedule/task/DocumentTask.java
  88. 66
      java/cloud/schedule/src/main/java/cn/toesbieya/jxc/schedule/task/SessionTask.java
  89. 116
      java/cloud/schedule/src/main/java/cn/toesbieya/jxc/schedule/task/StatisticTask.java
  90. 14
      java/cloud/schedule/src/main/resources/bootstrap.yml
  91. 100
      java/cloud/schedule/src/main/resources/mapper/Statistic.xml
  92. 51
      java/cloud/web/pom.xml
  93. 45
      java/cloud/web/web-common/pom.xml
  94. 10
      java/cloud/web/web-common/src/main/java/cn/toesbieya/jxc/web/common/annoation/Lock.java
  95. 10
      java/cloud/web/web-common/src/main/java/cn/toesbieya/jxc/web/common/annoation/TimeCost.java
  96. 10
      java/cloud/web/web-common/src/main/java/cn/toesbieya/jxc/web/common/annoation/UserAction.java
  97. 82
      java/cloud/web/web-common/src/main/java/cn/toesbieya/jxc/web/common/aspect/LockAspect.java
  98. 80
      java/cloud/web/web-common/src/main/java/cn/toesbieya/jxc/web/common/aspect/RestExceptionAspect.java
  99. 45
      java/cloud/web/web-common/src/main/java/cn/toesbieya/jxc/web/common/aspect/TimeCostAspect.java
  100. 74
      java/cloud/web/web-common/src/main/java/cn/toesbieya/jxc/web/common/aspect/UserActionAspect.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,6 @@
/target/
/.idea/
*.iml
.mvn
mvnw
*.cmd

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jxc</artifactId>
<groupId>cn.toesbieya</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api</artifactId>
<dependencies>
<dependency>
<groupId>cn.toesbieya</groupId>
<artifactId>common</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,20 @@
package cn.toesbieya.jxc.api.service;
import cn.toesbieya.jxc.api.vo.AttachmentOperation;
import cn.toesbieya.jxc.common.model.entity.RecAttachment;
import cn.toesbieya.jxc.common.model.entity.RecLoginHistory;
import cn.toesbieya.jxc.common.model.entity.RecUserAction;
import java.util.List;
public interface RecordApi {
List<RecAttachment> getAttachmentByPid(String pid);
void handleAttachment(AttachmentOperation vo);
void delAttachmentByPid(String pid);
void insertLoginHistory(RecLoginHistory vo);
void insertUserAction(RecUserAction vo);
}

@ -0,0 +1,18 @@
package cn.toesbieya.jxc.api.service;
import cn.toesbieya.jxc.common.model.entity.BizStock;
import cn.toesbieya.jxc.common.model.vo.StockOutboundVo;
import cn.toesbieya.jxc.common.model.vo.StockSearch;
import cn.toesbieya.jxc.common.model.vo.StockSearchResult;
import java.util.List;
public interface StockApi {
List<StockSearchResult> getByCondition(StockSearch vo);
List<BizStock> getDetail(String cids);
void inbound(List<BizStock> list);
void outbound(List<StockOutboundVo> list);
}

@ -0,0 +1,11 @@
package cn.toesbieya.jxc.api.service.system;
import cn.toesbieya.jxc.common.model.entity.SysRole;
import cn.toesbieya.jxc.common.model.vo.ResourceVo;
import java.util.List;
public interface ResourceApi {
//获取角色的权限列表,包含admin权限
List<ResourceVo> getResourceByRole(SysRole role);
}

@ -0,0 +1,7 @@
package cn.toesbieya.jxc.api.service.system;
import cn.toesbieya.jxc.common.model.entity.SysRole;
public interface RoleApi {
SysRole getRoleById(Integer roleId);
}

@ -0,0 +1,18 @@
package cn.toesbieya.jxc.api.vo;
import cn.toesbieya.jxc.common.model.entity.RecAttachment;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AttachmentOperation implements Serializable {
private static final long serialVersionUID = 1L;
private List<RecAttachment> uploadImageList;
private List<String> deleteImageList;
}

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jxc</artifactId>
<groupId>cn.toesbieya</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,19 @@
package cn.toesbieya.jxc.common.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
public class FastJsonConfigFactory {
public static FastJsonConfig defaultConfig() {
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(
SerializerFeature.WriteMapNullValue, // 是否输出值为null的字段
SerializerFeature.WriteDateUseDateFormat,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.DisableCircularReferenceDetect // 禁用循环引用
);
return config;
}
}

@ -0,0 +1,34 @@
package cn.toesbieya.jxc.common.config;
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
fastJsonRedisSerializer.setFastJsonConfig(FastJsonConfigFactory.defaultConfig());
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 设置值(value)的序列化采用FastJsonRedisSerializer。
redisTemplate.setValueSerializer(fastJsonRedisSerializer);
redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
// 设置键(key)的序列化采用StringRedisSerializer。
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setDefaultSerializer(fastJsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}

@ -0,0 +1,12 @@
package cn.toesbieya.jxc.common.constant;
public class DocumentConstant {
//更新单据ID时的redis锁的键
public static final String UPDATE_DOCUMENTS_LOCK_KEY = "UPDATE_DOCUMENTS";
//单据ID的redis缓存的键
public static final String DOCUMENT_TYPE_REDIS_KEY = "documentsID";
//单据类型
public static final String[] DOCUMENT_TYPE = {"CGDD", "CGRK", "CGTH", "XSDD", "XSCK", "XSTH"};
}

@ -0,0 +1,18 @@
package cn.toesbieya.jxc.common.constant;
public class SessionConstant {
//session过期时间,单位秒
public static long EXPIRE = 3600 * 8;
//存储用户信息的键的前缀
public static String REDIS_NAMESPACE = "sessions:";
//key过期事件的前缀
public static String REDIS_EXPIRE_TOPIC_PREFIX = "__keyspace@0__:";
//http headers中token的字段名
public static String TOKEN_KEY = "X-Token";
//区别无活动用户的时间间隔,单位秒
public static long NO_ACTION_INTERVAL = 1800;
}

@ -0,0 +1,23 @@
package cn.toesbieya.jxc.common.constant;
public class SocketConstant {
//web-socket服务端订阅的redis主题名称
public static String REDIS_EVENT_TOPIC_SEND = "socket-event-send";
//指定用户
public static int REDIS_EVENT_SPECIFIC = 0;
//广播
public static int REDIS_EVENT_BROADCAST = 1;
//登出
public static int REDIS_EVENT_LOGOUT = 2;
//存放于redis中的在线用户的ID集合的键
public static String REDIS_ONLINE_USER = "socket:online-user";
//存放于redis中的离线用户的离线时间的键
public static String REDIS_OFFLINE_USER = "socket:offline-user";
//登出事件
public static final String EVENT_LOGOUT = "logout";
//新消息事件
public static final String EVENT_NEW_MESSAGE = "new-message";
}

@ -0,0 +1,15 @@
package cn.toesbieya.jxc.common.enumeration;
public enum GeneralStatusEnum {
DISABLED(0), ENABLED(1);
private final int code;
GeneralStatusEnum(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}

@ -0,0 +1,7 @@
package cn.toesbieya.jxc.common.exception;
public class JsonResultException extends RuntimeException {
public JsonResultException(String message) {
super(message);
}
}

@ -0,0 +1,33 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
public class BizDoc implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private Integer cid;
private String cname;
private Long ctime;
private Integer vid;
private String vname;
private Long vtime;
private Integer status;
private String remark;
public BizDoc(BizDoc doc) {
this.id = doc.getId();
this.cid = doc.getCid();
this.cname = doc.getCname();
this.ctime = doc.getCtime();
this.vid = doc.getVid();
this.vname = doc.getVname();
this.vtime = doc.getVtime();
this.status = doc.getStatus();
this.remark = doc.getRemark();
}
}

@ -0,0 +1,25 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BizDocHistory implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String pid;
private Integer type;
private Integer uid;
private String uname;
private Integer status_before;
private Integer status_after;
private Long time;
private String info;
}

@ -0,0 +1,16 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
public class BizDocSub implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String pid;
private Integer cid;
private String cname;
private BigDecimal num;
}

@ -0,0 +1,19 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class BizPurchaseInbound extends BizDoc {
private String pid;
public BizPurchaseInbound(BizPurchaseInbound obj) {
super(obj);
this.pid = obj.getPid();
}
}

@ -0,0 +1,12 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class BizPurchaseInboundSub extends BizDocSub {
}

@ -0,0 +1,29 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.math.BigDecimal;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class BizPurchaseOrder extends BizDoc {
private Integer sid;
private String sname;
private Integer finish;
private Long ftime;
private BigDecimal total;
public BizPurchaseOrder(BizPurchaseOrder obj) {
super(obj);
this.sid = obj.getSid();
this.sname = obj.getSname();
this.finish = obj.getFinish();
this.ftime = obj.getFtime();
this.total = obj.getTotal();
}
}

@ -0,0 +1,15 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.math.BigDecimal;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class BizPurchaseOrderSub extends BizDocSub {
private BigDecimal price;
private BigDecimal remain_num;
}

@ -0,0 +1,29 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.math.BigDecimal;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class BizSellOrder extends BizDoc {
private Integer customer_id;
private String customer_name;
private Integer finish;
private Long ftime;
private BigDecimal total;
public BizSellOrder(BizSellOrder obj) {
super(obj);
this.customer_id = obj.getCustomer_id();
this.customer_name = obj.getCustomer_name();
this.finish = obj.getFinish();
this.ftime = obj.getFtime();
this.total = obj.getTotal();
}
}

@ -0,0 +1,15 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.math.BigDecimal;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class BizSellOrderSub extends BizDocSub {
private BigDecimal price;
private BigDecimal remain_num;
}

@ -0,0 +1,19 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class BizSellOutbound extends BizDoc {
private String pid;
public BizSellOutbound(BizSellOutbound obj) {
super(obj);
this.pid = obj.getPid();
}
}

@ -0,0 +1,12 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class BizSellOutboundSub extends BizDocSub {
private Integer sid;
}

@ -0,0 +1,25 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BizStock implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Integer cid;
private String cname;
private BigDecimal num;
private BigDecimal price;
private Long ctime;
private String cgrkid;
private String cgddid;
}

@ -0,0 +1,26 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class Msg implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String title;
private String content;
private Integer type;
private Integer cid;
private String cname;
private Long ctime;
private Integer pid;
private String pname;
private Long ptime;
private Integer wid;
private String wname;
private Long wtime;
private Integer status;
private Integer broadcast;
private String recipient;
}

@ -0,0 +1,14 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class MsgState implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Integer mid;
private Integer uid;
private Long time;
}

@ -0,0 +1,23 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RecAttachment implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String pid;
private String name;
private Long time;
private Integer sort;
private String url;
private Long size;
}

@ -0,0 +1,23 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RecLoginHistory implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Integer uid;
private String uname;
private String ip;
private String address;
private Integer type;
private Long time;
}

@ -0,0 +1,25 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RecUserAction implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Integer uid;
private String uname;
private String url;
private String ip;
private Long time;
private String action;
private String error;
private Integer type;
}

@ -0,0 +1,14 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class StatFinishOrder implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Integer purchase;
private Integer sell;
private Long time;
}

@ -0,0 +1,13 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class StatProfitGoods extends StatProfitTotal {
private Integer cid;
private String cname;
}

@ -0,0 +1,16 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
public class StatProfitTotal implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private BigDecimal purchase;
private BigDecimal sell;
private BigDecimal profit;
private Long time;
}

@ -0,0 +1,15 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class SysCategory implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Integer pid;
private String name;
private Integer type;
private Long ctime;
}

@ -0,0 +1,19 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class SysCustomer implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private String address;
private String linkman;
private String linkphone;
private String region;
private Integer status;
private Long ctime;
private String remark;
}

@ -0,0 +1,14 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class SysDepartment implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Integer pid;
private String name;
private Integer status;
}

@ -0,0 +1,15 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class SysRegion implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String pid;
private String name;
private String fullname;
private int level;
}

@ -0,0 +1,17 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class SysResource implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Integer pid;
private String name;
private String url;
private Integer admin;
private Long total_rate;
private Long ip_rate;
}

@ -0,0 +1,17 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class SysRole implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private String resource_id;
private Integer cid;
private String cname;
private Long ctime;
private Integer status;
}

@ -0,0 +1,19 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class SysSupplier implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private String address;
private String linkman;
private String linkphone;
private String region;
private Integer status;
private Long ctime;
private String remark;
}

@ -0,0 +1,22 @@
package cn.toesbieya.jxc.common.model.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SysUser implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private String pwd;
private Integer role;
private String avatar;
private Long ctime;
private Integer admin;
private Integer status;
}

@ -0,0 +1,9 @@
package cn.toesbieya.jxc.common.model.vo;
import lombok.Data;
@Data
public class BaseSearch {
private Integer page;
private Integer pageSize;
}

@ -0,0 +1,23 @@
package cn.toesbieya.jxc.common.model.vo;
import cn.toesbieya.jxc.common.model.entity.SysResource;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@NoArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class ResourceVo extends SysResource {
private String fullName;
public ResourceVo(SysResource parent) {
this.setId(parent.getId());
this.setPid(parent.getPid());
this.setName(parent.getName());
this.setUrl(parent.getUrl());
this.setAdmin(parent.getAdmin());
}
}

@ -0,0 +1,83 @@
package cn.toesbieya.jxc.common.model.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Result implements Serializable {
private static final long serialVersionUID = 1L;
//返回码,200表示成功,其他表示失败
private int status;
//返回的信息
private String msg;
//返回的数据
private Object data;
public Result(int status) {
this.status = status;
}
public Result(int status, String msg) {
this.status = status;
this.msg = msg;
}
public Result(int status, Object data) {
this.status = status;
this.data = data;
}
public static Result success() {
return new Result(200);
}
public static Result success(String msg) {
return new Result(200, msg);
}
public static Result success(Object data) {
return new Result(200, data);
}
public static Result success(String msg, Object data) {
return new Result(200, msg, data);
}
public static Result fail(String msg) {
return new Result(500, msg);
}
public static Result notfound() {
return new Result(404, "请求地址不存在");
}
public static Result requireLogin() {
return new Result(401, "请登录后重试");
}
public static Result noPermission() {
return new Result(403, "没有权限进行该操作");
}
public static Result overload() {
return new Result(503, "当前请求的人数过多,请稍后重试");
}
public static Result tooManyRequest() {
return new Result(429, "操作过于频繁,请稍后重试");
}
public boolean isSuccess() {
return this.status == 200;
}
}

@ -0,0 +1,21 @@
package cn.toesbieya.jxc.common.model.vo;
import cn.toesbieya.jxc.common.constant.SocketConstant;
import lombok.Data;
import java.util.List;
@Data
public class SocketEventVo {
//事件类型
private int type = SocketConstant.REDIS_EVENT_SPECIFIC;
//事件名称
private String event;
//发送对象的id集合
private List<Integer> to;
//数据包
private Object data;
}

@ -0,0 +1,16 @@
package cn.toesbieya.jxc.common.model.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SocketOfflineVo {
//用户的sessionKey
private String key;
//断开时间
private Long time;
}

@ -0,0 +1,17 @@
package cn.toesbieya.jxc.common.model.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class StockOutboundVo implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private BigDecimal num;
}

@ -0,0 +1,20 @@
package cn.toesbieya.jxc.common.model.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.Serializable;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class StockSearch extends BaseSearch implements Serializable {
private static final long serialVersionUID = 1L;
private String ids;
private String cids;
private Long startTime;
private Long endTime;
private String cgddids;
private String cgrkids;
}

@ -0,0 +1,15 @@
package cn.toesbieya.jxc.common.model.vo;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
public class StockSearchResult implements Serializable {
private static final long serialVersionUID = 1L;
private Integer cid;
private String cname;
private BigDecimal total_num;
private BigDecimal total_price;
}

@ -0,0 +1,31 @@
package cn.toesbieya.jxc.common.model.vo;
import cn.toesbieya.jxc.common.model.entity.SysUser;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.Set;
@Data
@NoArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class UserVo extends SysUser {
private String token;
private String role_name;
private boolean online = false;
private Set<Integer> resource_ids;
public UserVo(SysUser parent) {
this.setId(parent.getId());
this.setName(parent.getName());
this.setPwd(parent.getPwd());
this.setRole(parent.getRole());
this.setAvatar(parent.getAvatar());
this.setCtime(parent.getCtime());
this.setAdmin(parent.getAdmin());
this.setStatus(parent.getStatus());
}
}

@ -0,0 +1,53 @@
package cn.toesbieya.jxc.common.utils;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
public class DateUtil {
public static final DateTimeFormatter defaultFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static String dateFormat() {
return dateFormat(null, null);
}
public static String dateFormat(Long time) {
LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault());
return dateFormat(localDateTime, null);
}
public static String dateFormat(LocalDateTime time) {
return dateFormat(time, null);
}
public static String dateFormat(DateTimeFormatter formatter) {
return dateFormat(null, formatter);
}
public static String dateFormat(LocalDateTime time, DateTimeFormatter formatter) {
LocalDateTime t = time == null ? LocalDateTime.now() : time;
DateTimeFormatter f = formatter == null ? defaultFormatter : formatter;
return t.format(f);
}
//获取今日零点的时间戳
public static long getTimestampNow() {
long currentTimestamps = System.currentTimeMillis();
return currentTimestamps - (currentTimestamps + 60 * 60 * 8 * 1000) % (60 * 60 * 24 * 1000);
}
//获取n天前零点的时间戳
public static long getTimestampBeforeNow(int before) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.DATE, -before);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime().getTime();
}
}

@ -0,0 +1,176 @@
package cn.toesbieya.jxc.common.utils;
import com.google.common.io.ByteStreams;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import java.io.Closeable;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class RedisUtil {
private static String INCREMENT_AND_EXPIRE_SCRIPT;
private static RedisTemplate<String, Object> redisTemplate;
private static StringRedisTemplate stringRedisTemplate;
static {
try {
INCREMENT_AND_EXPIRE_SCRIPT = new String(ByteStreams.toByteArray(new ClassPathResource("/script/increase_and_expire.lua").getInputStream()));
}
catch (IOException e) {
e.printStackTrace();
}
}
@Autowired
public RedisUtil(RedisTemplate<String, Object> redisTemplate, StringRedisTemplate stringRedisTemplate) {
RedisUtil.redisTemplate = redisTemplate;
RedisUtil.stringRedisTemplate = stringRedisTemplate;
}
public static Set<String> keys(String match) {
return redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
Set<String> result = new HashSet<>();
Cursor<byte[]> cursor =
connection.scan(
new ScanOptions
.ScanOptionsBuilder()
.match(match)
.count(2000)
.build()
);
while (cursor.hasNext()) {
result.add(new String(cursor.next()));
}
return result;
});
}
public static boolean exist(String key) {
Boolean result = redisTemplate.hasKey(key);
return result != null && result;
}
public static void del(String... keys) {
redisTemplate.delete(Arrays.asList(keys));
}
public static long incrAndExpire(String key, int time) {
RedisScript<Long> redisScript = new DefaultRedisScript<>(INCREMENT_AND_EXPIRE_SCRIPT, Long.class);
Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), time);
return result == null ? 0 : result;
}
public static Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
public static void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
public static void set(String key, Object value, long expire) {
redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS);
}
public static Object hget(String key, String field) {
return redisTemplate.opsForHash().get(key, field);
}
public static Map<Object, Object> hgetAll(String key) {
return redisTemplate.opsForHash().entries(key);
}
public static void hset(String key, String field, Object value) {
redisTemplate.opsForHash().put(key, field, value);
}
public static void hdel(String key, Object... fields) {
redisTemplate.opsForHash().delete(key, fields);
}
public static List<Object> hmget(String key, String... field) {
return redisTemplate.opsForHash().multiGet(key, Arrays.asList(field));
}
public static void hmset(String key, Map<String, Object> map) {
redisTemplate.opsForHash().putAll(key, map);
}
public static long sadd(String key, Object... members) {
Long result = redisTemplate.opsForSet().add(key, members);
return result == null ? 0 : result;
}
public static void srem(String key, Object... members) {
redisTemplate.opsForSet().remove(key, members);
}
public static long scard(String key) {
Long result = redisTemplate.opsForSet().size(key);
return result == null ? 0 : result;
}
public static Set<Object> smembers(String key) {
Set<Object> result = redisTemplate.opsForSet().members(key);
return result == null ? Collections.emptySet() : result;
}
public static <T> T execute(RedisScript<T> script, List<String> keys, Object... args) {
return redisTemplate.execute(script, keys, args);
}
public static RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
public static StringRedisTemplate getStringRedisTemplate() {
return stringRedisTemplate;
}
public static class Locker implements Closeable {
private final String key;
private final String value;
private final long expire;
public Locker(String key) {
this.key = "lock:" + key;
this.value = String.valueOf(System.currentTimeMillis());
this.expire = 300;
}
@Override
public void close() {
this.unlock();
}
public boolean lock() {
String LOCK_LUA_SCRIPT = "return redis.call('set',KEYS[1],ARGV[1],'EX',ARGV[2],'NX')";
RedisScript<Boolean> redisScript = new DefaultRedisScript<>(LOCK_LUA_SCRIPT, Boolean.class);
Boolean result = redisTemplate.execute(redisScript, Collections.singletonList(key), value, expire);
return result != null;
}
public void unlock() {
String UNLOCK_LUA_SCRIPT = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return false end";
RedisScript<Boolean> redisScript = new DefaultRedisScript<>(UNLOCK_LUA_SCRIPT, Boolean.class);
Boolean result = redisTemplate.execute(redisScript, Collections.singletonList(key), value);
if (result == null || !result) {
log.error("redis锁释放失败,key:{},value:{}", key, value);
}
}
}
}

@ -0,0 +1,57 @@
package cn.toesbieya.jxc.common.utils;
import cn.toesbieya.jxc.common.model.entity.SysUser;
import cn.toesbieya.jxc.common.model.vo.UserVo;
import com.alibaba.fastjson.JSONObject;
import cn.toesbieya.jxc.common.constant.SessionConstant;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
public class SessionUtil {
//token中的连接符
private static final String tokenSeparator = "-*-";
public static void remove(String token) {
if (StringUtils.isEmpty(token)) return;
RedisUtil.del(SessionConstant.REDIS_NAMESPACE + token);
}
public static void save(UserVo user) {
String token = user.getToken();
if (StringUtils.isEmpty(token)) return;
RedisUtil.set(SessionConstant.REDIS_NAMESPACE + token, user, SessionConstant.EXPIRE);
}
public static UserVo get(String token) {
if (StringUtils.isEmpty(token)) return null;
JSONObject o = (JSONObject) RedisUtil.get(SessionConstant.REDIS_NAMESPACE + token);
if (o == null) return null;
return JSONObject.toJavaObject(o, UserVo.class);
}
public static UserVo get(HttpServletRequest request) {
String token = request.getHeader(SessionConstant.TOKEN_KEY);
return get(token);
}
public static String generateToken(SysUser user) {
return user.getId() + tokenSeparator + Util.UUID();
}
public static Integer getUidFromToken(String token) {
if (StringUtils.isEmpty(token)) {
return null;
}
String[] arr = token.split(tokenSeparator);
return arr.length > 1 ? Integer.valueOf(arr[0]) : null;
}
}

@ -0,0 +1,29 @@
package cn.toesbieya.jxc.common.utils;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;
public class SpringUtil {
private static final ExpressionParser parser = new SpelExpressionParser();
/**
* el表达式解析
*
* @param el 表达式
* @param names 参数名称数组
* @param args 参数数组
*/
public static Object spell(String el, String[] names, Object[] args) {
if (StringUtils.isEmpty(el)) {
return null;
}
EvaluationContext context = new StandardEvaluationContext();
for (int i = 0; i < args.length; i++) {
context.setVariable(names[i], args[i]);
}
return parser.parseExpression(el).getValue(context);
}
}

@ -0,0 +1,72 @@
package cn.toesbieya.jxc.common.utils;
import org.springframework.util.StringUtils;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class Util {
public static String UUID() {
return UUID.randomUUID().toString();
}
public static List<Integer> str2List(String string) {
if (StringUtils.isEmpty(string)) {
return Collections.emptyList();
}
return Arrays.stream(string.split(","))
.map(i -> Integer.parseInt(i.trim()))
.collect(Collectors.toList());
}
public static String str2Hex(String s) {
byte[] baKeyword = new byte[s.length() / 2];
for (int i = 0; i < baKeyword.length; i++) {
baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
}
return new String(baKeyword, StandardCharsets.ISO_8859_1);
}
public static boolean isInteger(String str) {
Pattern pattern = Pattern.compile("^[-+]?[\\d]*$");
return pattern.matcher(str).matches();
}
public static String exception2Str(Exception e) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
printWriter.close();
return stringWriter.toString();
}
public static <T> T find(Iterable<T> list, Predicate<T> predicate) {
for (T t : list) {
if (predicate.test(t)) return t;
}
return null;
}
public static <T> int findIndex(Iterable<T> list, Predicate<T> predicate) {
int i = -1;
if (list == null) return i;
for (T t : list) {
i++;
if (predicate.test(t)) return i;
}
return -1;
}
public static <T> boolean some(Iterable<T> list, Predicate<T> predicate) {
int index = findIndex(list, predicate);
return index > -1;
}
}

@ -0,0 +1,36 @@
package cn.toesbieya.jxc.common.utils;
import cn.toesbieya.jxc.common.model.vo.SocketEventVo;
import cn.toesbieya.jxc.common.constant.SocketConstant;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class WebSocketUtil {
//获取在线用户的总数
public static long getOnlineUserNum() {
return RedisUtil.scard(SocketConstant.REDIS_ONLINE_USER);
}
//获取所有在线用户的id集合
public static Set<Integer> getOnlineUserIds() {
Set<Object> result = RedisUtil.smembers(SocketConstant.REDIS_ONLINE_USER);
return result.stream().map(e -> (Integer) e).collect(Collectors.toSet());
}
//发送消息
public static void sendEvent(SocketEventVo vo) {
RedisUtil.getRedisTemplate().convertAndSend(SocketConstant.REDIS_EVENT_TOPIC_SEND, vo);
}
//登出
public static void sendLogoutEvent(List<Integer> to, String msg) {
SocketEventVo vo = new SocketEventVo();
vo.setEvent(SocketConstant.EVENT_LOGOUT);
vo.setTo(to);
vo.setData(msg);
sendEvent(vo);
}
}

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jxc</artifactId>
<groupId>cn.toesbieya</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway</artifactId>
<dependencies>
<dependency>
<groupId>cn.toesbieya</groupId>
<artifactId>common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>-->
</dependencies>
</project>

@ -0,0 +1,13 @@
package cn.toesbieya.jxc.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication(scanBasePackages = "cn.toesbieya.jxc")
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}

@ -0,0 +1,19 @@
package cn.toesbieya.jxc.gateway.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;
@Component
@ConfigurationProperties("spring.cloud.gateway")
@Data
public class GatewayConfig {
private Set<String> whitelist = new HashSet<>();
private String dataId = "jxc-gateway.yml";
private String group = "DEFAULT_GROUP";
}

@ -0,0 +1,14 @@
package cn.toesbieya.jxc.gateway.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;
@Configuration
public class RateConfig {
@Bean
public KeyResolver urlKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
}

@ -0,0 +1,97 @@
package cn.toesbieya.jxc.gateway.config;
import cn.toesbieya.jxc.common.model.entity.SysResource;
import cn.toesbieya.jxc.common.model.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@Component
@Slf4j
public class ResourceConfig implements CommandLineRunner {
private final static ConcurrentHashMap<String, Integer> urlMap = new ConcurrentHashMap<>(256);
private final static ConcurrentHashMap<String, Integer> adminUrlMap = new ConcurrentHashMap<>(16);
private static JdbcTemplate jdbcTemplate;
public static boolean authority(UserVo user, String url) {
//超级管理员放行
if (user.getAdmin() == 1) {
return true;
}
//普通用户访问admin权限的资源时拦截
if (adminUrlMap.containsKey(url)) {
return false;
}
//权限表中无记录的资源放行
if (!urlMap.containsKey(url)) {
return true;
}
Set<Integer> ids = user.getResource_ids();
return ids != null && ids.contains(urlMap.get(url));
}
@Override
public void run(String... args) throws Exception {
init(false);
}
public static void init(boolean clear) {
Instant start = Instant.now();
if (clear) {
urlMap.clear();
adminUrlMap.clear();
}
String sql = "select id,pid,url,admin from sys_resource";
List<SysResource> resources = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(SysResource.class));
completeNode(resources);
for (SysResource p : resources) {
if (p.getAdmin().equals(1)) {
adminUrlMap.put(p.getUrl(), p.getId());
}
else urlMap.put(p.getUrl(), p.getId());
}
Instant end = Instant.now();
log.info("权限资源加载完成,耗时:{}毫秒", ChronoUnit.MILLIS.between(start, end));
}
@Autowired
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
ResourceConfig.jdbcTemplate = jdbcTemplate;
}
private static void completeNode(List<SysResource> list) {
HashMap<Integer, String> url = new HashMap<>(128);
for (SysResource resource : list) {
//pid为0时跳过
if (resource.getPid() == 0) {
url.put(resource.getId(), resource.getUrl());
continue;
}
//获取父节点进行拼接
String parentUrl = url.get(resource.getPid());
resource.setUrl(parentUrl + resource.getUrl());
url.put(resource.getId(), resource.getUrl());
}
}
}

@ -0,0 +1,138 @@
package cn.toesbieya.jxc.gateway.config;
import cn.toesbieya.jxc.gateway.filter.SecurityFilter;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;
import reactor.core.publisher.Mono;
import javax.annotation.PostConstruct;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
@Component
@Slf4j
public class RouteConfig implements ApplicationEventPublisherAware {
@Value("${spring.cloud.nacos.config.server-addr}")
private String NACOS_SERVER_ADDR;
private GatewayConfig config;
private RouteDefinitionWriter writer;
private ApplicationEventPublisher publisher;
@PostConstruct
public void addListener() throws NacosException {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, NACOS_SERVER_ADDR);
ConfigService configService = NacosFactory.createConfigService(properties);
configService.addListener(config.getDataId(), config.getGroup(), new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
@SuppressWarnings("unchecked")
public void receiveConfigInfo(String configInfo) {
Yaml yaml = new Yaml();
Map<String, Object> config = yaml.load(configInfo);
config = (Map<String, Object>) config.get("spring");
config = (Map<String, Object>) config.get("cloud");
config = (Map<String, Object>) config.get("gateway");
SecurityFilter.updateWhitelist((List<String>) config.get("whitelist"));
List<Map<String, Object>> routes = (List<Map<String, Object>>) config.get("routes");
if (routes == null) return;
List<RouteDefinition> list =
routes
.stream()
.map(map -> {
RouteDefinition route = new RouteDefinition();
route.setId((String) map.get("id"));
route.setUri(URI.create((String) map.get("uri")));
List<String> predicates = (List<String>) map.get("predicates");
if (predicates != null) {
route.setPredicates(
predicates
.stream()
.map(PredicateDefinition::new)
.collect(Collectors.toList())
);
}
List<String> filters = (List<String>) map.get("filters");
if (filters != null) {
route.setFilters(
filters
.stream()
.map(FilterDefinition::new)
.collect(Collectors.toList())
);
}
return route;
})
.collect(Collectors.toList());
update(list);
//SentinelFilter.registerRules(list);
}
});
}
private void update(List<RouteDefinition> routes) {
if (routes == null) return;
routes.forEach(route -> {
this.writer.delete(Mono.just(route.getId()));
writer.save(Mono.just(route)).subscribe();
});
this.publisher.publishEvent(new RefreshRoutesEvent(this));
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@Autowired
public void setWriter(RouteDefinitionWriter writer) {
this.writer = writer;
}
@Autowired
public void setGatewayProperties(GatewayConfig config) {
this.config = config;
}
}

@ -0,0 +1,13 @@
package cn.toesbieya.jxc.gateway.controller;
import cn.toesbieya.jxc.common.model.vo.Result;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
public class FallbackController {
@RequestMapping("fallback")
@ResponseBody
public Result fallback() {
return Result.fail("服务异常");
}
}

@ -0,0 +1,106 @@
package cn.toesbieya.jxc.gateway.filter;
import cn.toesbieya.jxc.common.model.vo.UserVo;
import cn.toesbieya.jxc.gateway.config.GatewayConfig;
import cn.toesbieya.jxc.gateway.config.ResourceConfig;
import com.alibaba.fastjson.JSON;
import cn.toesbieya.jxc.common.constant.SessionConstant;
import cn.toesbieya.jxc.common.model.vo.Result;
import cn.toesbieya.jxc.common.utils.SessionUtil;
import cn.toesbieya.jxc.common.utils.Util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import static org.springframework.http.server.PathContainer.parsePath;
@Component
@Slf4j
public class SecurityFilter {
private GatewayConfig gatewayConfig;
private static final PathPatternParser pathPatternParser = new PathPatternParser();
private static List<PathPattern> whitelistPatterns = new ArrayList<>();
@Bean
@Order(-1)
public GlobalFilter globalFilter() {
updateWhitelist(gatewayConfig.getWhitelist());
return ((exchange, chain) -> {
String requestUrl = exchange.getRequest().getURI().getPath();
PathContainer path = parsePath(requestUrl);
//放行白名单内的url
if (Util.some(whitelistPatterns, pattern -> pattern.matches(path))) {
return chain.filter(exchange);
}
ServerHttpResponse response = exchange.getResponse();
String token = exchange.getRequest().getHeaders().getFirst(SessionConstant.TOKEN_KEY);
UserVo user = SessionUtil.get(token);
//未登录
if (user == null) {
return responseJSON(response, Result.requireLogin());
}
//没有权限
if (!ResourceConfig.authority(user, requestUrl)) {
return responseJSON(response, Result.noPermission());
}
return chain.filter(exchange);
});
}
private Mono<Void> responseJSON(ServerHttpResponse response, Result result) {
byte[] bytes = JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(bytes);
response.setStatusCode(HttpStatus.OK);
response.getHeaders().add("Content-Type", "application/json; charset=utf-8");
return response.writeWith(Mono.just(buffer));
}
public static void updateWhitelist(Collection<String> list) {
if (list == null) {
whitelistPatterns = new ArrayList<>();
return;
}
whitelistPatterns =
list
.stream()
.map(pathPatternParser::parse)
.collect(Collectors.toList());
}
@Autowired
public void setGatewayProperties(GatewayConfig gatewayConfig) {
this.gatewayConfig = gatewayConfig;
}
}

@ -0,0 +1,68 @@
package cn.toesbieya.jxc.gateway.filter;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SentinelFilter {
/*private GatewayProperties gatewayProperties;
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public SentinelFilter(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
@PostConstruct
public void init() {
registerRules(gatewayProperties.getRoutes());
GatewayCallbackManager.setBlockHandler(
(exchange, t) ->
ServerResponse
.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(fromObject(Result.tooManyRequest()))
);
}
public static void registerRules(List<RouteDefinition> routes) {
Set<GatewayFlowRule> rules = new HashSet<>();
routes.forEach(route -> {
String id = route.getId();
rules.add(new GatewayFlowRule(id).setCount(100));
rules.add(
new GatewayFlowRule(id)
.setCount(1)
.setParamItem(
new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_CLIENT_IP)
)
);
});
GatewayRuleManager.register2Property(new DynamicSentinelProperty<>(rules));
}
@Autowired
public void setGatewayProperties(GatewayProperties gatewayProperties) {
this.gatewayProperties = gatewayProperties;
}*/
}

@ -0,0 +1,15 @@
spring:
application:
name: jxc-gateway
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
shared-configs:
- data-id: jxc-common-database.yml
- data-id: jxc-common-redis.yml
file-extension: yml
discovery:
server-addr: 127.0.0.1:8848

@ -0,0 +1,25 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/repo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
username: username
password: password
mybatis-plus:
mapper-locations:
- classpath*:/mapper/**/*.xml
configuration:
map-underscore-to-camel-case: false
local-cache-scope: STATEMENT
cache-enabled: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
banner: false
db-config:
id-type: NONE
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql

@ -0,0 +1,8 @@
qiniu:
access-key:
secret-key:
bucket:
#七牛的临时上传凭证的有效期,单位秒
token-expires: 3600
#七牛的临时上传凭证的redis键名
redis-cache-key: qiniu-token

@ -0,0 +1,11 @@
spring:
redis:
host: localhost
port: 6379
timeout: 3000
lettuce:
pool:
max-idle: 500
min-idle: 50
max-active: 2000
max-wait: 1000

@ -0,0 +1,60 @@
server:
port: 8081
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
lowerCaseServiceId: true
default-filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒处理多少个请求
redis-rate-limiter.burstCapacity: 20 # 一秒钟内完成的最大请求数
key-resolver: #{@urlKeyResolver}
routes:
- id: jxc-web-account
uri: lb://jxc-web-account
predicates:
- Path=/account/**
- id: jxc-web-document
uri: lb://jxc-web-document
predicates:
- Path=/document/**
- id: jxc-web-message
uri: lb://jxc-web-message
predicates:
- Path=/message/**
- id: jxc-web-record
uri: lb://jxc-web-record
predicates:
- Path=/record/**
- id: jxc-web-statistic
uri: lb://jxc-web-statistic
predicates:
- Path=/statistic/**
- id: jxc-web-stock
uri: lb://jxc-web-stock
predicates:
- Path=/stock/**
- id: jxc-web-system
uri: lb://jxc-web-system
predicates:
- Path=/system/**
whitelist:
- /test/**
- /account/login
- /account/logout
- /account/register
- /account/checkName

@ -0,0 +1,4 @@
server:
port: 8001
servlet:
context-path: /document

@ -0,0 +1,4 @@
server:
port: 8002
servlet:
context-path: /message

@ -0,0 +1,4 @@
server:
port: 8006
servlet:
context-path: /system

@ -0,0 +1,6 @@
socket:
#hostname: 172.24.52.184
hostname: localhost
port: 12580
max-frame-payload-length: 1048576
max-http-content-length: 1048576

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<packaging>pom</packaging>
<modules>
<module>common</module>
<module>gateway</module>
<module>web</module>
<module>websocket</module>
<module>schedule</module>
<module>api</module>
</modules>
<groupId>cn.toesbieya</groupId>
<artifactId>jxc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jxc</name>
<properties>
<java.version>1.8</java.version>
<spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
<mybatis-plus.version>3.3.2</mybatis-plus.version>
<pagehelper.version>1.2.12</pagehelper.version>
<socketio.version>1.7.11</socketio.version>
<guava.version>28.1-jre</guava.version>
<fastjson.version>1.2.60</fastjson.version>
<!--七牛云-->
<qiniu.version>[7.2.0, 7.2.99]</qiniu.version>
<!--三方工具-->
<easyexcel.version>2.2.5</easyexcel.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.toesbieya</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.toesbieya</groupId>
<artifactId>web-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.toesbieya</groupId>
<artifactId>api</artifactId>
<version>${project.version}</version>
</dependency>
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>${qiniu.version}</version>
</dependency>
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>${socketio.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jxc</artifactId>
<groupId>cn.toesbieya</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>shedule</artifactId>
<dependencies>
<dependency>
<groupId>cn.toesbieya</groupId>
<artifactId>common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,16 @@
package cn.toesbieya.jxc.schedule;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
@SpringBootApplication(scanBasePackages = "cn.toesbieya.jxc")
@MapperScan("cn.toesbieya.jxc.schedule.mapper")
public class ScheduleApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ScheduleApplication.class)
.web(WebApplicationType.NONE)
.run(args);
}
}

@ -0,0 +1,45 @@
package cn.toesbieya.jxc.schedule.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) -> {
log.error("异步线程执行失败。方法:[{}],异常信息[{}] : ", method, ex.getMessage(), ex);
};
}
//定时任务线程池
@Bean
public Executor scheduledExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
//核心线程数
threadPoolTaskExecutor.setCorePoolSize(3);
//是否回收空闲线程
threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
//最大线程数
threadPoolTaskExecutor.setMaxPoolSize(5);
//配置等待队列大小
threadPoolTaskExecutor.setQueueCapacity(2);
//配置线程池前缀
threadPoolTaskExecutor.setThreadNamePrefix("scheduled-");
//拒绝策略
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}

@ -0,0 +1,33 @@
package cn.toesbieya.jxc.schedule.mapper;
import cn.toesbieya.jxc.common.model.entity.StatFinishOrder;
import cn.toesbieya.jxc.common.model.entity.StatProfitGoods;
import cn.toesbieya.jxc.common.model.entity.StatProfitTotal;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.List;
public interface StatisticMapper {
boolean checkDailyFinishOrderExist(@Param("time") long time);
boolean checkDailyProfitExist(@Param("time") long time);
int insertFinishOrder(StatFinishOrder param);
int insertProfitTotal(StatProfitTotal param);
int insertProfitGoodsBatch(@Param("list") List<StatProfitGoods> list);
BigDecimal getPurchaseOrderDailyTotalPurchasePrice(@Param("start") Long start, @Param("end") Long end);
List<StatProfitGoods> getPurchaseOrderDailyProfitGoods(@Param("start") long start, @Param("end") long end);
Integer getPurchaseOrderLastDayFinishOrderNum();
BigDecimal getSellOrderDailyTotalPurchasePrice(@Param("start") Long start, @Param("end") Long end);
List<StatProfitGoods> getSellOrderDailyProfitGoods(@Param("start") long start, @Param("end") long end);
Integer getSellOrderLastDayFinishOrderNum();
}

@ -0,0 +1,106 @@
package cn.toesbieya.jxc.schedule.task;
import cn.toesbieya.jxc.common.constant.DocumentConstant;
import cn.toesbieya.jxc.common.utils.DateUtil;
import cn.toesbieya.jxc.common.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.DependsOn;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
@Slf4j
@DependsOn("redisUtil")
public class DocumentTask implements CommandLineRunner {
@Override
public void run(String... args) {
template("初始化单据ID", 0);
}
//每天零点重置单据ID的值
@Async("scheduledExecutor")
@Scheduled(cron = "1 0 0 */1 * ?")
public void autoRefreshDocumentID() {
template("定时更新单据ID", 1);
}
//启动时初始化单据ID
private void initDocumentsID() {
String[] fields = new String[DocumentConstant.DOCUMENT_TYPE.length + 1];
fields[0] = "date";
System.arraycopy(DocumentConstant.DOCUMENT_TYPE, 0, fields, 1, fields.length - 1);
List<Object> result = RedisUtil.hmget(DocumentConstant.DOCUMENT_TYPE_REDIS_KEY, fields);
long now = DateUtil.getTimestampNow();
//日期不是今天时,更新全部
Object firstItem = result.get(0);
if (null == firstItem || now != (long) firstItem) {
updateAllDocument(now);
log.info("更新【{}】种单据ID成功", DocumentConstant.DOCUMENT_TYPE.length);
return;
}
//判断是否有新增的单据类型,有则更新
int updateNum = 0;
Map<String, Object> update = new HashMap<>();
int resultSize = result.size();
for (int i = 1; i < resultSize; i++) {
if (result.get(i) == null) {
updateNum++;
update.put(DocumentConstant.DOCUMENT_TYPE[i - 1], 1);
}
}
if (updateNum > 0) {
RedisUtil.hmset(DocumentConstant.DOCUMENT_TYPE_REDIS_KEY, update);
log.info("更新增加的单据【{}】种", updateNum);
}
}
//每种单据的值置为1
private void updateAllDocument(long now) {
Map<String, Object> map = new HashMap<>();
map.put("date", now);
for (String v : DocumentConstant.DOCUMENT_TYPE) {
map.put(v, 1);
}
RedisUtil.hmset(DocumentConstant.DOCUMENT_TYPE_REDIS_KEY, map);
}
//模板
private void template(String action, int type) {
Instant start = Instant.now();
String lockKey = DocumentConstant.UPDATE_DOCUMENTS_LOCK_KEY;
try (RedisUtil.Locker locker = new RedisUtil.Locker(lockKey)) {
if (!locker.lock()) {
log.error("{}失败,获取锁【{}】失败", action, lockKey);
return;
}
if (type == 0) {
initDocumentsID();
}
else {
updateAllDocument(DateUtil.getTimestampNow());
}
log.info("{}成功,耗时:{}毫秒", action, ChronoUnit.MILLIS.between(start, Instant.now()));
}
catch (Exception e) {
log.error("{}失败", action, e);
}
}
}

@ -0,0 +1,66 @@
package cn.toesbieya.jxc.schedule.task;
import cn.toesbieya.jxc.common.constant.SessionConstant;
import cn.toesbieya.jxc.common.constant.SocketConstant;
import cn.toesbieya.jxc.common.model.vo.SocketOfflineVo;
import cn.toesbieya.jxc.common.utils.RedisUtil;
import cn.toesbieya.jxc.common.utils.SessionUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.DependsOn;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Set;
@Component
@Slf4j
@DependsOn("redisUtil")
public class SessionTask implements CommandLineRunner {
@Override
public void run(String... args) {
cleanSession();
}
@Async("scheduledExecutor")
@Scheduled(cron = "0 */10 * * * ?")
public void autoCleanSession() {
cleanSession();
}
//清理session中未活动的用户
private void cleanSession() {
try {
long now = System.currentTimeMillis();
//获取所有用户session
Set<String> sessionKeys = RedisUtil.keys(SessionConstant.REDIS_NAMESPACE + "*");
//获取离线情况 (k:sessionKey,v:SocketOfflineVo)
Map<Object, Object> offlineMap = RedisUtil.hgetAll(SocketConstant.REDIS_OFFLINE_USER);
//移除无活动时间超出限定的用户
sessionKeys.forEach(sessionKey -> {
Object obj = offlineMap.get(sessionKey);
if (obj != null) {
SocketOfflineVo offlineVo = ((JSONObject) obj).toJavaObject(SocketOfflineVo.class);
if (now > offlineVo.getTime() + SessionConstant.NO_ACTION_INTERVAL) {
//删除session
RedisUtil.del(sessionKey);
//删除离线表信息
String token = sessionKey.replace(SessionConstant.REDIS_NAMESPACE, "");
Integer uid = SessionUtil.getUidFromToken(token);
RedisUtil.hdel(SocketConstant.REDIS_OFFLINE_USER, String.valueOf(uid));
}
}
});
}
catch (Exception e) {
log.error("清理session失败", e);
}
}
}

@ -0,0 +1,116 @@
package cn.toesbieya.jxc.schedule.task;
import cn.toesbieya.jxc.common.model.entity.StatFinishOrder;
import cn.toesbieya.jxc.common.model.entity.StatProfitGoods;
import cn.toesbieya.jxc.common.model.entity.StatProfitTotal;
import cn.toesbieya.jxc.common.utils.DateUtil;
import cn.toesbieya.jxc.schedule.mapper.StatisticMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
@Slf4j
public class StatisticTask implements CommandLineRunner {
@Resource
private StatisticMapper statisticMapper;
@Override
public void run(String... args) throws Exception {
this.autoStat();
}
//每天零点统计信息
@Async("scheduledExecutor")
@Scheduled(cron = "1 0 0 */1 * ?")
public void autoStat() {
log.info("开始统计信息...");
long lastDay = DateUtil.getTimestampBeforeNow(1);
long today = DateUtil.getTimestampNow();
//检查是否已统计过昨日已完成的订单数
if (!statisticMapper.checkDailyFinishOrderExist(lastDay)) {
Integer lastDayPurchaseOrderFinish = statisticMapper.getPurchaseOrderLastDayFinishOrderNum();
Integer lastDaySellOrderFinish = statisticMapper.getSellOrderLastDayFinishOrderNum();
StatFinishOrder param = new StatFinishOrder();
param.setPurchase(lastDayPurchaseOrderFinish);
param.setSell(lastDaySellOrderFinish);
param.setTime(lastDay);
statisticMapper.insertFinishOrder(param);
}
//检查是否已统计过昨日的采购额、销售额、毛利
if (!statisticMapper.checkDailyProfitExist(lastDay)) {
//昨日各个商品的采购额、销售额
List<StatProfitGoods> purchaseProfitGoods = statisticMapper.getPurchaseOrderDailyProfitGoods(lastDay, today);
List<StatProfitGoods> sellProfitGoods = statisticMapper.getSellOrderDailyProfitGoods(lastDay, today);
//昨日的采购总额、销售总额
BigDecimal totalPurchase = new BigDecimal(0);
BigDecimal totalSell = new BigDecimal(0);
//根据商品分类计算
Map<Integer, StatProfitGoods> map = new HashMap<>(sellProfitGoods.size());
for (StatProfitGoods p : sellProfitGoods) {
map.put(p.getCid(), p);
}
for (StatProfitGoods p : purchaseProfitGoods) {
p.setTime(lastDay);
Integer cid = p.getCid();
BigDecimal purchase = p.getPurchase();
totalPurchase = totalPurchase.add(purchase);
StatProfitGoods s = map.get(cid);
if (s != null) {
BigDecimal sell = s.getSell();
totalSell = totalSell.add(sell);
p.setSell(sell);
p.setProfit(sell.subtract(purchase));
map.remove(cid);
}
else {
p.setSell(new BigDecimal(0));
p.setProfit(p.getSell().subtract(purchase));
}
}
for (StatProfitGoods s : map.values()) {
s.setTime(lastDay);
s.setPurchase(new BigDecimal(0));
BigDecimal sell = s.getSell();
s.setProfit(sell);
totalSell = totalSell.add(sell);
purchaseProfitGoods.add(s);
}
BigDecimal totalProfit = totalSell.subtract(totalPurchase);
StatProfitTotal statProfitTotal = new StatProfitTotal();
statProfitTotal.setPurchase(totalPurchase);
statProfitTotal.setSell(totalSell);
statProfitTotal.setProfit(totalProfit);
statProfitTotal.setTime(lastDay);
statisticMapper.insertProfitTotal(statProfitTotal);
if (purchaseProfitGoods.size() > 0) {
statisticMapper.insertProfitGoodsBatch(purchaseProfitGoods);
}
}
log.info("结束统计信息...");
}
}

@ -0,0 +1,14 @@
spring:
application:
name: jxc-schedule
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yml
shared-configs:
- data-id: jxc-common-database.yml
- data-id: jxc-common-redis.yml
discovery:
server-addr: 127.0.0.1:8848

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.toesbieya.jxc.schedule.mapper.StatisticMapper">
<select id="checkDailyFinishOrderExist" resultType="java.lang.Boolean">
select count(0)
from stat_finish_order
where time = #{time}
</select>
<select id="checkDailyProfitExist" resultType="java.lang.Boolean">
select count(0)
from stat_profit_total
where time = #{time}
</select>
<insert id="insertFinishOrder" parameterType="cn.toesbieya.jxc.common.model.entity.StatFinishOrder">
insert into stat_finish_order (purchase, sell, time)
values (#{purchase}, #{sell}, #{time})
</insert>
<insert id="insertProfitTotal" parameterType="cn.toesbieya.jxc.common.model.entity.StatProfitTotal">
insert into stat_profit_total (purchase, sell, profit, time)
values (#{purchase}, #{sell}, #{profit}, #{time})
</insert>
<insert id="insertProfitGoodsBatch" keyColumn="id" keyProperty="id"
parameterType="cn.toesbieya.jxc.common.model.entity.StatProfitGoods"
useGeneratedKeys="true">
insert into stat_profit_goods
(cid, purchase, sell, profit, time)
values
<foreach collection="list" item="item" separator=",">
(#{item.cid}, #{item.purchase}, #{item.sell}, #{item.profit}, #{item.time})
</foreach>
</insert>
<select id="getPurchaseOrderDailyTotalPurchasePrice" resultType="java.math.BigDecimal">
select ifnull(sum(total), 0) total
from biz_purchase_order
where status = 2
<if test="start != null">
and vtime <![CDATA[ >= ]]> #{start}
</if>
<if test="end != null">
and vtime <![CDATA[ <= ]]> #{end}
</if>
</select>
<select id="getPurchaseOrderLastDayFinishOrderNum" resultType="java.lang.Integer">
select count(0)
from biz_purchase_order
where status = 2
and finish = 2
and ftime between unix_timestamp(cast(sysdate() as date) - interval 1 day) * 1000 and unix_timestamp(cast(sysdate() as date)) * 1000
</select>
<select id="getPurchaseOrderDailyProfitGoods" resultType="cn.toesbieya.jxc.common.model.entity.StatProfitGoods">
select t1.*,
t2.name cname
from (select a.cid,
ifnull(sum(a.num * a.price), 0) purchase
from biz_purchase_order_sub a
join biz_purchase_order b on a.pid = b.id
where b.vtime between #{start} and #{end}
group by a.cid) t1
join sys_category t2 on t1.cid = t2.id
</select>
<select id="getSellOrderDailyTotalPurchasePrice" resultType="java.math.BigDecimal">
select ifnull(sum(total), 0) total
from biz_sell_order
where status = 2
<if test="start != null">
and vtime <![CDATA[ >= ]]> #{start}
</if>
<if test="end != null">
and vtime <![CDATA[ <= ]]> #{end}
</if>
</select>
<select id="getSellOrderLastDayFinishOrderNum" resultType="java.lang.Integer">
select count(0)
from biz_sell_order
where status = 2
and finish = 2
and ftime between unix_timestamp(cast(sysdate() as date) - interval 1 day) * 1000 and unix_timestamp(cast(sysdate() as date)) * 1000
</select>
<select id="getSellOrderDailyProfitGoods" resultType="cn.toesbieya.jxc.common.model.entity.StatProfitGoods">
select t1.*,
t2.name cname
from (select a.cid,
ifnull(sum(a.num * a.price), 0) sell
from biz_sell_order_sub a
join biz_sell_order b on a.pid = b.id
where b.vtime between #{start} and #{end}
group by a.cid) t1
join sys_category t2 on t1.cid = t2.id
</select>
</mapper>

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jxc</artifactId>
<groupId>cn.toesbieya</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<packaging>pom</packaging>
<modules>
<module>web-modules</module>
<module>web-common</module>
</modules>
<modelVersion>4.0.0</modelVersion>
<artifactId>web</artifactId>
<dependencies>
<dependency>
<groupId>cn.toesbieya</groupId>
<artifactId>common</artifactId>
</dependency>
<dependency>
<groupId>cn.toesbieya</groupId>
<artifactId>api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<exclusions>
<exclusion>
<artifactId>jackson-dataformat-xml</artifactId>
<groupId>com.fasterxml.jackson.dataformat</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>web</artifactId>
<groupId>cn.toesbieya</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>web-common</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,10 @@
package cn.toesbieya.jxc.web.common.annoation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lock {
String[] value() default {};
}

@ -0,0 +1,10 @@
package cn.toesbieya.jxc.web.common.annoation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TimeCost {
}

@ -0,0 +1,10 @@
package cn.toesbieya.jxc.web.common.annoation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserAction {
String value() default "";
}

@ -0,0 +1,82 @@
package cn.toesbieya.jxc.web.common.aspect;
import cn.toesbieya.jxc.common.model.vo.Result;
import cn.toesbieya.jxc.common.utils.RedisUtil;
import cn.toesbieya.jxc.common.utils.SpringUtil;
import cn.toesbieya.jxc.web.common.annoation.Lock;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.util.ArrayList;
@Component
@Aspect
@Slf4j
@Order(Integer.MAX_VALUE - 1)
public class LockAspect {
private final ThreadLocal<ArrayList<RedisUtil.Locker>> lockHelperThreadLocal = new ThreadLocal<>();
@Pointcut("@annotation(cn.toesbieya.jxc.web.common.annoation.Lock)&&execution(cn.toesbieya.jxc.common.model.vo.Result cn.toesbieya.jxc..*.*(..))")
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
String[] values = method.getAnnotation(Lock.class).value();
if (values.length <= 0) {
return point.proceed();
}
ArrayList<RedisUtil.Locker> locks = new ArrayList<>();
String[] parameterNames = signature.getParameterNames();
Object[] args = point.getArgs();
for (String v : values) {
String lockKey = (String) SpringUtil.spell(v, parameterNames, args);
//跳过空值
if (StringUtils.isEmpty(lockKey)) continue;
RedisUtil.Locker lockHelper = new RedisUtil.Locker(lockKey);
if (!lockHelper.lock()) {
locks.forEach(RedisUtil.Locker::close);
return Result.fail("操作失败,请刷新后重试");
}
locks.add(lockHelper);
}
lockHelperThreadLocal.set(locks);
return point.proceed();
}
@AfterReturning("pointCut()")
public void afterReturning() {
unlock();
}
@AfterThrowing("pointCut()")
public void afterThrowing() {
unlock();
}
private void unlock() {
ArrayList<RedisUtil.Locker> locks = lockHelperThreadLocal.get();
if (!CollectionUtils.isEmpty(locks)) {
locks.forEach(RedisUtil.Locker::close);
lockHelperThreadLocal.remove();
}
}
}

@ -0,0 +1,80 @@
package cn.toesbieya.jxc.web.common.aspect;
import cn.toesbieya.jxc.api.service.RecordApi;
import cn.toesbieya.jxc.common.exception.JsonResultException;
import cn.toesbieya.jxc.common.model.entity.RecUserAction;
import cn.toesbieya.jxc.common.model.vo.Result;
import cn.toesbieya.jxc.common.utils.Util;
import cn.toesbieya.jxc.web.common.enumeration.UserActionEnum;
import cn.toesbieya.jxc.web.common.utils.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
@Slf4j
@RestControllerAdvice
public class RestExceptionAspect {
@Reference
private RecordApi recordApi;
//抛出异常时希望返回给前台
@ExceptionHandler(JsonResultException.class)
public Result handle(JsonResultException e) {
recordUserAction(e);
return Result.fail(e.getMessage());
}
//请求方法有误
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public Result handle(HttpRequestMethodNotSupportedException e) {
return Result.fail("请求方法有误");
}
//@RequestParam没有匹配到值
@ExceptionHandler(MissingServletRequestParameterException.class)
public Result handle(MissingServletRequestParameterException e) {
log.error(e.getMessage(),e);
return Result.fail("get参数有误");
}
//@RequestBody没有匹配到值
@ExceptionHandler(HttpMessageNotReadableException.class)
public Result handle(HttpMessageNotReadableException e) {
log.error(e.getMessage(),e);
return Result.fail("post参数有误");
}
//上传文件过大
@ExceptionHandler(MaxUploadSizeExceededException.class)
public Result handle(MaxUploadSizeExceededException e) {
log.error("上传的文件超出限定大小,{}", e.getMessage());
recordUserAction(e);
return Result.fail("上传的文件过大");
}
//最终捕获
@ExceptionHandler(Exception.class)
public Result handle(Exception e) {
log.error("服务运行异常", e);
recordUserAction(e);
return Result.fail("服务运行异常");
}
private void recordUserAction(Exception e) {
RecUserAction action = ThreadUtil.getAction();
if (action != null && !StringUtils.isEmpty(action.getAction())) {
action.setError(Util.exception2Str(e));
action.setType(UserActionEnum.FAIL.getCode());
recordApi.insertUserAction(action);
}
ThreadUtil.clearAll();
}
}

@ -0,0 +1,45 @@
package cn.toesbieya.jxc.web.common.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
@Component
@Aspect
@Slf4j
@Order(1)
public class TimeCostAspect {
private final ThreadLocal<Instant> instantThreadLocal = new ThreadLocal<>();
@Pointcut("@annotation(cn.toesbieya.jxc.web.common.annoation.TimeCost)")
public void pointCut() {
}
@Before("pointCut()")
public void before() {
instantThreadLocal.set(Instant.now());
}
@AfterReturning("pointCut()")
public void afterReturning(JoinPoint point) {
if (null != instantThreadLocal.get()) {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
log.info("类:{},方法:{},耗时:{}毫秒",
method.getDeclaringClass().getName(),
method.getName(),
ChronoUnit.MILLIS.between(instantThreadLocal.get(), Instant.now()));
}
}
}

@ -0,0 +1,74 @@
package cn.toesbieya.jxc.web.common.aspect;
import cn.toesbieya.jxc.api.service.RecordApi;
import cn.toesbieya.jxc.common.model.entity.RecUserAction;
import cn.toesbieya.jxc.common.model.vo.Result;
import cn.toesbieya.jxc.common.utils.SpringUtil;
import cn.toesbieya.jxc.web.common.annoation.UserAction;
import cn.toesbieya.jxc.web.common.enumeration.UserActionEnum;
import cn.toesbieya.jxc.web.common.utils.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
@Component
@Aspect
@Slf4j
@Order(Integer.MAX_VALUE - 2)
public class UserActionAspect {
@Reference
private RecordApi recordApi;
@Pointcut("@annotation(cn.toesbieya.jxc.web.common.annoation.UserAction)&&execution(cn.toesbieya.jxc.common.model.vo.Result cn.toesbieya.jxc..*.*(..))")
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
RecUserAction action = ThreadUtil.getAction();
if (action == null) {
return pjp.proceed();
}
action.setTime(System.currentTimeMillis());
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
Object[] args = pjp.getArgs();
String[] argNames = signature.getParameterNames();
UserAction annotation = method.getAnnotation(UserAction.class);
//优先使用注解表达式
if (!StringUtils.isEmpty(annotation.value())) {
String str = (String) SpringUtil.spell(annotation.value(), argNames, args);
if (!StringUtils.isEmpty(str)) {
action.setAction(str);
}
}
Result result = (Result) pjp.proceed();
if (result.isSuccess()) {
action.setType(UserActionEnum.SUCCESS.getCode());
}
else {
action.setType(UserActionEnum.FAIL.getCode());
action.setError(result.getMsg());
}
recordApi.insertUserAction(action);
return result;
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save