parent
6c7599acfc
commit
1c25927a1f
@ -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,2 @@ |
|||||||
|
server: |
||||||
|
port: 8000 |
||||||
@ -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,2 @@ |
|||||||
|
server: |
||||||
|
port: 8003 |
||||||
@ -0,0 +1,2 @@ |
|||||||
|
server: |
||||||
|
port: 8004 |
||||||
@ -0,0 +1,2 @@ |
|||||||
|
server: |
||||||
|
port: 8005 |
||||||
@ -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…
Reference in new issue