init
This commit is contained in:
3
sl-express-common/.gitignore
vendored
Normal file
3
sl-express-common/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.idea
|
||||
target/
|
||||
*.iml
|
||||
62
sl-express-common/pom.xml
Normal file
62
sl-express-common/pom.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<?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>
|
||||
<groupId>com.sl-express</groupId>
|
||||
<artifactId>sl-express-parent</artifactId>
|
||||
<version>1.4</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<version>1.2-SNAPSHOT</version>
|
||||
<groupId>com.sl-express.common</groupId>
|
||||
<artifactId>sl-express-common</artifactId>
|
||||
<description>神领物流的通用工程,提供一些通用的类或工具。</description>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<sl-express-common.version>1.2-SNAPSHOT</sl-express-common.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun.oss</groupId>
|
||||
<artifactId>aliyun-sdk-oss</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.itheima.em.auth</groupId>
|
||||
<artifactId>itcast-auth-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.sl.transport.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented //标记注解
|
||||
public @interface NoAuthorization {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.sl.transport.common.aspect;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
import com.sl.transport.common.util.AspectUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validator;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 请求参数校验切面,统一对Controller中@RequestBody映射的对象进行校验,在Controller方法中无需单独处理
|
||||
*/
|
||||
@Aspect
|
||||
@Slf4j
|
||||
@EnableAspectJAutoProxy
|
||||
@Component
|
||||
public class ValidatedAspect {
|
||||
|
||||
@Resource
|
||||
private Validator validator;
|
||||
|
||||
@Around("execution(* com.sl..controller.*Controller.*(..))")
|
||||
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
|
||||
// 获取@RequestBody映射的对象
|
||||
Object body = AspectUtil.getBody(proceedingJoinPoint);
|
||||
// 不为空的body进行拦截校验
|
||||
if (!ObjectUtil.isEmpty(body)) {
|
||||
// 进行校验
|
||||
Set<ConstraintViolation<Object>> validateResult = validator.validate(body);
|
||||
if (CollUtil.isNotEmpty(validateResult)) {
|
||||
//没有通过校验,抛出异常,由统一异常处理机制进行处理,响应400
|
||||
String info = JSONUtil.toJsonStr(validateResult.stream()
|
||||
.map(ConstraintViolation::getMessage).collect(Collectors.toList()));
|
||||
throw new SLException(info, HttpStatus.BAD_REQUEST.value());
|
||||
}
|
||||
}
|
||||
//校验通过,执行原方法
|
||||
return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.sl.transport.common.config;
|
||||
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
|
||||
/**
|
||||
* 通用解码器实现
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
public class CommonFeignErrorDecoder extends FeignErrorDecoder {
|
||||
|
||||
@Override
|
||||
public Exception call(int status, int code, String msg) {
|
||||
return new SLException(msg, code, status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.sl.transport.common.config;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import feign.Response;
|
||||
import feign.codec.ErrorDecoder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Feign解码器
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class FeignErrorDecoder implements ErrorDecoder {
|
||||
|
||||
public abstract Exception call(int status, int code, String msg);
|
||||
|
||||
@Override
|
||||
public Exception decode(String methodKey, Response response) {
|
||||
String message = null;
|
||||
try {
|
||||
message = IoUtil.read(response.body().asReader(CharsetUtil.CHARSET_UTF_8));
|
||||
log.info("methodKey {} response {}", methodKey, message);
|
||||
JSONObject jsonObject = JSONUtil.parseObj(message);
|
||||
return this.call(response.status(), jsonObject.getInt("code"), jsonObject.getStr("msg"));
|
||||
} catch (Exception e) {
|
||||
//出现网络中断、服务宕机
|
||||
String msg = StrUtil.format("Feign调用失败,methodKey = {}, message = {}", methodKey, message);
|
||||
return this.call(response.status(), -1, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.sl.transport.common.config;
|
||||
|
||||
import com.sl.transport.common.properties.SwaggerConfigProperties;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.service.Contact;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(value = SwaggerConfigProperties.class)
|
||||
public class Knife4jConfiguration {
|
||||
|
||||
@Resource
|
||||
private SwaggerConfigProperties swaggerConfigProperties;
|
||||
|
||||
@Bean(value = "defaultApi2")
|
||||
public Docket defaultApi2() {
|
||||
Docket docket = new Docket(DocumentationType.SWAGGER_2)
|
||||
.apiInfo(new ApiInfoBuilder()
|
||||
.title(this.swaggerConfigProperties.getTitle())
|
||||
.description(this.swaggerConfigProperties.getDescription())
|
||||
.contact(new Contact(
|
||||
this.swaggerConfigProperties.getContactName(),
|
||||
this.swaggerConfigProperties.getContactUrl(),
|
||||
this.swaggerConfigProperties.getContactEmail()))
|
||||
.version(this.swaggerConfigProperties.getVersion())
|
||||
.build())
|
||||
.select()
|
||||
//这里指定Controller扫描包路径
|
||||
.apis(RequestHandlerSelectors.basePackage(swaggerConfigProperties.getPackagePath()))
|
||||
.paths(PathSelectors.any())
|
||||
.build();
|
||||
return docket;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.sl.transport.common.config;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix = "spring.datasource", value = "url")
|
||||
public class MybatisPlusConfig {
|
||||
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
|
||||
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
|
||||
//设置分页插件
|
||||
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
|
||||
|
||||
//防全表更新与删除插件
|
||||
mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
|
||||
return mybatisPlusInterceptor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.sl.transport.common.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
||||
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
|
||||
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
|
||||
return builder -> {
|
||||
// 序列化
|
||||
builder.serializerByType(Long.class, ToStringSerializer.instance);
|
||||
builder.serializerByType(BigInteger.class, ToStringSerializer.instance);
|
||||
builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
|
||||
builder.serializerByType(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
|
||||
builder.serializerByType(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
|
||||
|
||||
// 反序列化
|
||||
builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
|
||||
builder.deserializerByType(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
|
||||
builder.deserializerByType(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果在工程中没有设置解码器,统一使用通用解码器,
|
||||
* 如果不想使用通用解码器就在工程中自定义FeignErrorDecoder子类,并且标注 @Configuration 注解
|
||||
*
|
||||
* @return Feign调用失败的解码器
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public FeignErrorDecoder feignErrorDecoder() {
|
||||
return new CommonFeignErrorDecoder();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
package com.sl.transport.common.constant;
|
||||
|
||||
/**
|
||||
* 常量类
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
public abstract class Constants {
|
||||
|
||||
public interface LOCKS {
|
||||
/**
|
||||
* 任务调度锁的前缀
|
||||
*/
|
||||
String DISPATCH_LOCK_PREFIX = "DISPATCH_LOCK_";
|
||||
|
||||
/**
|
||||
* 司机作业单锁前缀
|
||||
*/
|
||||
String DRIVER_JOB_LOCK_PREFIX = "DRIVER_JOB_LOCK_";
|
||||
}
|
||||
|
||||
public interface GATEWAY{
|
||||
|
||||
String USER_ID = "userId";
|
||||
String USERINFO = "userInfo";
|
||||
String TOKEN = "token";
|
||||
String AUTHORIZATION = "Authorization";
|
||||
String ACCESS_TOKEN = "access_token";
|
||||
String REFRESH_TOKEN = "refresh_token";
|
||||
}
|
||||
|
||||
public interface MQ {
|
||||
|
||||
/**
|
||||
* 默认延时时间为-1
|
||||
*/
|
||||
int DEFAULT_DELAY = -1;
|
||||
|
||||
/**
|
||||
* 低延迟时间:5秒
|
||||
*/
|
||||
int LOW_DELAY = 5000;
|
||||
|
||||
/**
|
||||
* 标准延迟时间:10秒
|
||||
*/
|
||||
int NORMAL_DELAY = 10000;
|
||||
|
||||
/**
|
||||
* 延迟交换机关键字
|
||||
*/
|
||||
String DELAYED_KEYWORD = "delayed";
|
||||
|
||||
/**
|
||||
* 表明是延迟队列
|
||||
*/
|
||||
String DELAYED = "true";
|
||||
|
||||
/**
|
||||
* 定义消息交换机,约定:1:类型都为topic,2:延迟队列命名由.delayed结尾
|
||||
*/
|
||||
interface Exchanges {
|
||||
/**
|
||||
* 订单
|
||||
*/
|
||||
String ORDER_DELAYED = "sl.exchange.topic.order.delayed";
|
||||
|
||||
/**
|
||||
* 运单
|
||||
*/
|
||||
String TRANSPORT_ORDER_DELAYED = "sl.exchange.topic.transportOrder.delayed";
|
||||
|
||||
/**
|
||||
* 运输任务
|
||||
*/
|
||||
String TRANSPORT_TASK = "sl.exchange.topic.transportTask";
|
||||
|
||||
/**
|
||||
* 运输路线、机构等
|
||||
*/
|
||||
String TRANSPORT = "sl.exchange.topic.transport";
|
||||
|
||||
/**
|
||||
* 物流信息等
|
||||
*/
|
||||
String TRANSPORT_INFO = "sl.exchange.topic.transportInfo";
|
||||
|
||||
/**
|
||||
* 司机作业单
|
||||
*/
|
||||
String DRIVER_JOB = "sl.exchange.topic.driverJob";
|
||||
|
||||
/**
|
||||
* 取派件任务(延时)
|
||||
*/
|
||||
String PICKUP_DISPATCH_TASK_DELAYED = "sl.exchange.topic.pickupDispatchTask.delayed";
|
||||
|
||||
/**
|
||||
* 快递员
|
||||
*/
|
||||
String COURIER = "sl.exchange.topic.courier";
|
||||
|
||||
/**
|
||||
* 司机
|
||||
*/
|
||||
String DRIVER = "sl.exchange.topic.driver";
|
||||
|
||||
/**
|
||||
* 用户
|
||||
*/
|
||||
String USER = "sl.exchange.topic.user";
|
||||
|
||||
/**
|
||||
* 车辆
|
||||
*/
|
||||
String TRUCK = "sl.exchange.topic.truck";
|
||||
|
||||
/**
|
||||
* 车辆计划
|
||||
*/
|
||||
String TRUCK_PLAN = "sl.exchange.topic.truckPlan";
|
||||
|
||||
/**
|
||||
* 系统
|
||||
*/
|
||||
String SYSTEM = "sl.exchange.topic.system";
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
String ERROR = "sl.exchange.topic.error";
|
||||
|
||||
/**
|
||||
* 交易(支付)
|
||||
*/
|
||||
String TRADE = "sl.exchange.topic.trade";
|
||||
|
||||
/**
|
||||
* 快递员任务
|
||||
*/
|
||||
String COURIER_TASK = "sl.exchange.topic.courierTask";
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义消息队列
|
||||
*/
|
||||
interface Queues {
|
||||
|
||||
/**
|
||||
* 调度中心:订单转取/派件任务
|
||||
*/
|
||||
String DISPATCH_ORDER_TO_PICKUP_DISPATCH_TASK = "sl.queue.dispatch.order.pickupDispatchTask";
|
||||
|
||||
/**
|
||||
* 调度中心:合并运单队列
|
||||
*/
|
||||
String DISPATCH_MERGE_TRANSPORT_ORDER = "sl.queue.dispatch.mergeTransportOrder";
|
||||
|
||||
/**
|
||||
* 基础微服务:完成车辆计划
|
||||
*/
|
||||
String BASE_TRUCK_PLAN_COMPLETE = "sl.queue.base.truckPlan.complete";
|
||||
|
||||
/**
|
||||
* work微服务:生成快递员的取件、派件任务
|
||||
*/
|
||||
String WORK_PICKUP_DISPATCH_TASK_CREATE = "sl.queue.work.pickupDispatchTask.create";
|
||||
|
||||
/**
|
||||
* work微服务:创建运输任务
|
||||
*/
|
||||
String WORK_TRANSPORT_TASK_CREATE = "sl.queue.work.transportTask.create";
|
||||
|
||||
/**
|
||||
* work微服务:取件成功
|
||||
*/
|
||||
String WORK_COURIER_PICKUP_SUCCESS = "sl.queue.work.courier.pickup.success";
|
||||
|
||||
/**
|
||||
* 物流信息微服务:追加物流信息
|
||||
*/
|
||||
String TRANSPORT_INFO_APPEND = "sl.queue.transportInfo.append";
|
||||
|
||||
/**
|
||||
* 轨迹服务:创建运单
|
||||
*/
|
||||
String TRACK_TRANSPORT_ORDER_CREATED = "sl.queue.track.transportOrder.created";
|
||||
|
||||
/**
|
||||
* 轨迹服务:更新运单状态
|
||||
*/
|
||||
String TRACK_TRANSPORT_ORDER_UPDATE_STATUS = "sl.queue.track.transportOrder.update.status";
|
||||
|
||||
/**
|
||||
* 订单微服务:快递员取件后更新订单
|
||||
*/
|
||||
String OMS_COURIER_PICKUP_UPDATE_ORDER = "sl.queue.oms.courier.pickup.update.order";
|
||||
|
||||
/**
|
||||
* 订单微服务:更新运单状态
|
||||
*/
|
||||
String OMS_TRANSPORT_ORDER_UPDATE_STATUS = "sl.queue.oms.transportOrder.update.status";
|
||||
|
||||
/**
|
||||
* 订单微服务:更新支付状态
|
||||
*/
|
||||
String OMS_TRADE_UPDATE_STATUS = "sl.queue.oms.trade.update.Status";
|
||||
|
||||
/**
|
||||
* 订单微服务:更新退款
|
||||
*/
|
||||
String OMS_TRADE_REFUND_STATUS = "sl.queue.oms.trade.refund";
|
||||
|
||||
/**
|
||||
* 错误消息队列前缀
|
||||
*/
|
||||
String ERROR_PREFIX = "sl.queue.error.";
|
||||
|
||||
/**
|
||||
* 权限系统机构消息队列
|
||||
*/
|
||||
String AUTH_TRANSPORT = "sl.queue.auth.transport";
|
||||
|
||||
/**
|
||||
* 权限系统机构消息队列
|
||||
*/
|
||||
String AUTH_USER = "sl.queue.auth.user";
|
||||
|
||||
/**
|
||||
* 搜索微服务:快递员任务新增/更新
|
||||
*/
|
||||
String COURIER_TASK_SAVE_OR_UPDATE = "sl.queue.search.courierTask.saveOrUpdate";
|
||||
|
||||
/**
|
||||
* 搜索微服务:创建运单
|
||||
*/
|
||||
String SEARCH_TRANSPORT_ORDER_CREATED = "sl.queue.search.transportOrder.created";
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义路由key
|
||||
*/
|
||||
interface RoutingKeys {
|
||||
/**
|
||||
* 运单加入到调度
|
||||
*/
|
||||
String JOIN_DISPATCH = "JOIN_DISPATCH";
|
||||
|
||||
/**
|
||||
* 创建运输任务
|
||||
*/
|
||||
String TRANSPORT_TASK_CREATE = "CREATE";
|
||||
|
||||
/**
|
||||
* 快递员取件
|
||||
*/
|
||||
String COURIER_PICKUP = "PICKUP";
|
||||
|
||||
/**
|
||||
* 快递员取件后更新订单
|
||||
*/
|
||||
String COURIER_UPDATE_ORDER = "UPDATE_ORDER";
|
||||
|
||||
/**
|
||||
* 快递员派件
|
||||
*/
|
||||
String COURIER_DISPATCH = "DISPATCH";
|
||||
|
||||
/**
|
||||
* 完成车辆计划
|
||||
*/
|
||||
String TRUCK_PLAN_COMPLETE = "COMPLETE";
|
||||
|
||||
/**
|
||||
* 新增订单
|
||||
*/
|
||||
String ORDER_CREATE = "CREATE";
|
||||
|
||||
/**
|
||||
* 生成取/派件任务
|
||||
*/
|
||||
String PICKUP_DISPATCH_TASK_CREATE = "CREATE";
|
||||
|
||||
/**
|
||||
* 追加物流信息
|
||||
*/
|
||||
String TRANSPORT_INFO_APPEND = "APPEND";
|
||||
|
||||
/**
|
||||
* 新增运单
|
||||
*/
|
||||
String TRANSPORT_ORDER_CREATE = "CREATE";
|
||||
|
||||
/**
|
||||
* 更新运单状态
|
||||
*/
|
||||
String TRANSPORT_ORDER_UPDATE_STATUS_PREFIX = "UPDATE_STATUS.";
|
||||
|
||||
/**
|
||||
* 更新支付状态
|
||||
*/
|
||||
String TRADE_UPDATE_STATUS = "UPDATE_STATUS";
|
||||
|
||||
/**
|
||||
* 更新退款状态
|
||||
*/
|
||||
String REFUND_UPDATE_STATUS = "REFUND_UPDATE_STATUS";
|
||||
|
||||
/**
|
||||
* 新增/更新快递员任务
|
||||
*/
|
||||
String COURIER_TASK_SAVE_OR_UPDATE = "saveOrUpdate";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.sl.transport.common.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
public abstract class BaseEntity implements Serializable {
|
||||
|
||||
@TableId
|
||||
private Long id; //主键id
|
||||
|
||||
@TableField(fill = FieldFill.INSERT) //MP自动填充
|
||||
private LocalDateTime created;
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updated;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.sl.transport.common.enums;
|
||||
|
||||
/**
|
||||
* 所有的枚举都需要实现此接口
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
public interface BaseEnum {
|
||||
|
||||
/**
|
||||
* 业务状态码
|
||||
*/
|
||||
Integer getCode();
|
||||
|
||||
/**
|
||||
* 业务说明
|
||||
*/
|
||||
String getValue();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.sl.transport.common.enums;
|
||||
|
||||
/**
|
||||
* 所有的错异常类型枚举都需要实现该接口
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
public interface BaseExceptionEnum extends BaseEnum {
|
||||
|
||||
/**
|
||||
* http响应状态码
|
||||
*/
|
||||
Integer getStatus();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.sl.transport.common.enums;
|
||||
|
||||
/**
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
public enum IdEnum implements BaseEnum {
|
||||
|
||||
TRANSPORT_ORDER(1, "运单号", "transport_order", "segment", "SL");
|
||||
|
||||
private Integer code;
|
||||
private String value;
|
||||
private String biz; //业务名称
|
||||
private String type; //类型:自增长(segment),雪花id(snowflake)
|
||||
private String prefix;//id前缀
|
||||
|
||||
IdEnum(Integer code, String value, String biz, String type, String prefix) {
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
this.biz = biz;
|
||||
this.type = type;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getBiz() {
|
||||
return biz;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("IdEnum{");
|
||||
sb.append("code=").append(code);
|
||||
sb.append(", value='").append(value).append('\'');
|
||||
sb.append(", biz='").append(biz).append('\'');
|
||||
sb.append(", type='").append(type).append('\'');
|
||||
sb.append(", prefix='").append(prefix).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.sl.transport.common.exception;
|
||||
|
||||
import com.sl.transport.common.enums.BaseEnum;
|
||||
import com.sl.transport.common.enums.BaseExceptionEnum;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 自定义异常
|
||||
*/
|
||||
@Data
|
||||
public class SLException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String msg; //异常中的信息
|
||||
private int code = 1001; //业务状态码,规则:4位数,从1001开始递增
|
||||
private int status = 500; //http状态码,按照http协议规范,如:200,201,400等
|
||||
|
||||
public SLException(BaseEnum baseEnum) {
|
||||
super(baseEnum.getValue());
|
||||
this.msg = baseEnum.getValue();
|
||||
this.code = baseEnum.getCode();
|
||||
}
|
||||
|
||||
public SLException(BaseEnum baseEnum, Throwable e) {
|
||||
super(baseEnum.getValue(), e);
|
||||
this.msg = baseEnum.getValue();
|
||||
this.code = baseEnum.getCode();
|
||||
}
|
||||
|
||||
public SLException(BaseExceptionEnum errorEnum) {
|
||||
super(errorEnum.getValue());
|
||||
this.status = errorEnum.getStatus();
|
||||
this.msg = errorEnum.getValue();
|
||||
this.code = errorEnum.getCode();
|
||||
}
|
||||
|
||||
public SLException(BaseExceptionEnum errorEnum, Throwable e) {
|
||||
super(errorEnum.getValue(), e);
|
||||
this.status = errorEnum.getStatus();
|
||||
this.msg = errorEnum.getValue();
|
||||
this.code = errorEnum.getCode();
|
||||
}
|
||||
|
||||
public SLException(String msg) {
|
||||
super(msg);
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public SLException(String msg, Throwable e) {
|
||||
super(msg, e);
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public SLException(String msg, int code) {
|
||||
super(msg);
|
||||
this.msg = msg;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public SLException(String msg, int code, int status) {
|
||||
super(msg);
|
||||
this.msg = msg;
|
||||
this.code = code;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public SLException(String msg, int code, Throwable e) {
|
||||
super(msg, e);
|
||||
this.msg = msg;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public SLException(String msg, int code, int status, Throwable e) {
|
||||
super(msg, e);
|
||||
this.msg = msg;
|
||||
this.code = code;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.sl.transport.common.exception;
|
||||
|
||||
import com.sl.transport.common.enums.BaseEnum;
|
||||
import com.sl.transport.common.enums.BaseExceptionEnum;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 自定义异常
|
||||
*/
|
||||
@Data
|
||||
public class SLWebException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String msg; //异常中的信息
|
||||
private int code = 1; //业务状态码,规则:异常弹窗状态码
|
||||
private int status = 200; //http状态码,按照http协议规范,如:200,201,400等
|
||||
|
||||
public SLWebException(BaseEnum baseEnum) {
|
||||
super(baseEnum.getValue());
|
||||
this.msg = baseEnum.getValue();
|
||||
this.code = baseEnum.getCode();
|
||||
}
|
||||
|
||||
public SLWebException(BaseEnum baseEnum, Throwable e) {
|
||||
super(baseEnum.getValue(), e);
|
||||
this.msg = baseEnum.getValue();
|
||||
this.code = baseEnum.getCode();
|
||||
}
|
||||
|
||||
public SLWebException(BaseExceptionEnum errorEnum) {
|
||||
super(errorEnum.getValue());
|
||||
this.status = errorEnum.getStatus();
|
||||
this.msg = errorEnum.getValue();
|
||||
this.code = errorEnum.getCode();
|
||||
}
|
||||
|
||||
public SLWebException(BaseExceptionEnum errorEnum, Throwable e) {
|
||||
super(errorEnum.getValue(), e);
|
||||
this.status = errorEnum.getStatus();
|
||||
this.msg = errorEnum.getValue();
|
||||
this.code = errorEnum.getCode();
|
||||
}
|
||||
|
||||
public SLWebException(String msg) {
|
||||
super(msg);
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public SLWebException(String msg, Throwable e) {
|
||||
super(msg, e);
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public SLWebException(String msg, int code) {
|
||||
super(msg);
|
||||
this.msg = msg;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public SLWebException(String msg, int code, int status) {
|
||||
super(msg);
|
||||
this.msg = msg;
|
||||
this.code = code;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public SLWebException(String msg, int code, Throwable e) {
|
||||
super(msg, e);
|
||||
this.msg = msg;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public SLWebException(String msg, int code, int status, Throwable e) {
|
||||
super(msg, e);
|
||||
this.msg = msg;
|
||||
this.code = code;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.sl.transport.common.handler;
|
||||
|
||||
/**
|
||||
* 特殊类型转换器
|
||||
*/
|
||||
public interface ConvertHandler<O, T> {
|
||||
/**
|
||||
* 特殊对象类型转换
|
||||
*
|
||||
* @param originObject 源对象
|
||||
* @param targetObject 目标对象
|
||||
*/
|
||||
void map(O originObject, T targetObject);
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.sl.transport.common.handler;
|
||||
|
||||
import cn.hutool.core.exceptions.ExceptionUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
import com.sl.transport.common.exception.SLWebException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.validation.ValidationException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestControllerAdvice
|
||||
@Slf4j
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 参数校验失败异常
|
||||
*
|
||||
* @param exception 校验失败异常
|
||||
* @return 响应数据
|
||||
*/
|
||||
@ExceptionHandler(ValidationException.class)
|
||||
public ResponseEntity<Object> handle(ValidationException exception) {
|
||||
List<String> errors = null;
|
||||
if (exception instanceof ConstraintViolationException) {
|
||||
ConstraintViolationException exs = (ConstraintViolationException) exception;
|
||||
Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
|
||||
errors = violations.stream()
|
||||
.map(ConstraintViolation::getMessage).collect(Collectors.toList());
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(exception.getCause())) {
|
||||
log.error("参数校验失败异常 -> ", exception);
|
||||
}
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
|
||||
.body(MapUtil.<String, Object>builder()
|
||||
.put("code", HttpStatus.BAD_REQUEST.value())
|
||||
.put("msg", errors)
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义异常处理
|
||||
*
|
||||
* @param exception 自定义异常
|
||||
* @return 响应数据
|
||||
*/
|
||||
@ExceptionHandler(SLException.class)
|
||||
public ResponseEntity<Object> handle(SLException exception) {
|
||||
if (ObjectUtil.isNotEmpty(exception.getCause())) {
|
||||
log.error("自定义异常处理 -> ", exception);
|
||||
}
|
||||
return ResponseEntity.status(exception.getStatus())
|
||||
.body(MapUtil.<String, Object>builder()
|
||||
.put("code", exception.getCode())
|
||||
.put("msg", exception.getMsg())
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* web自定义异常处理
|
||||
* 用于统一封装VO对象返回前端
|
||||
*
|
||||
* @param exception web自定义异常
|
||||
* @return 响应数据
|
||||
*/
|
||||
@ExceptionHandler(SLWebException.class)
|
||||
public ResponseEntity<Object> handle(SLWebException exception) {
|
||||
if (ObjectUtil.isNotEmpty(exception.getCause())) {
|
||||
log.error("自定义异常处理 -> ", exception);
|
||||
}
|
||||
JSONObject jsonObject = JSONUtil.parseObj(exception);
|
||||
return ResponseEntity.ok(MapUtil.<String, Object>builder()
|
||||
.put("code", exception.getCode())
|
||||
.put("msg", jsonObject.getStr("msg"))
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传超过最大限制异常
|
||||
*
|
||||
* @param exception 未知异常
|
||||
* @return 响应数据
|
||||
*/
|
||||
@ExceptionHandler(MaxUploadSizeExceededException.class)
|
||||
public ResponseEntity<Object> handle(MaxUploadSizeExceededException exception) {
|
||||
if (ObjectUtil.isNotEmpty(exception.getCause())) {
|
||||
log.error("文件上传超过最大限制异常 -> ", exception);
|
||||
}
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(MapUtil.<String, Object>builder()
|
||||
.put("code", HttpStatus.INTERNAL_SERVER_ERROR.value())
|
||||
.put("msg", "上传图片大小不能超过5M,格式需为jpg、png、gif")
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 其他未知异常
|
||||
*
|
||||
* @param exception 未知异常
|
||||
* @return 响应数据
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<Object> handle(Exception exception) {
|
||||
if (ObjectUtil.isNotEmpty(exception.getCause())) {
|
||||
log.error("其他未知异常 -> ", exception);
|
||||
}
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(MapUtil.<String, Object>builder()
|
||||
.put("code", HttpStatus.INTERNAL_SERVER_ERROR.value())
|
||||
.put("msg", ExceptionUtil.stacktraceToString(exception))
|
||||
.build());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.sl.transport.common.handler;
|
||||
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Component
|
||||
public class MyMetaObjectHandler implements MetaObjectHandler {
|
||||
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
Object created = getFieldValByName("created", metaObject);
|
||||
if (null == created) {
|
||||
//字段为空,可以进行填充
|
||||
setFieldValByName("created", LocalDateTime.now(), metaObject);
|
||||
}
|
||||
|
||||
Object updated = getFieldValByName("updated", metaObject);
|
||||
if (null == updated) {
|
||||
//字段为空,可以进行填充
|
||||
setFieldValByName("updated", LocalDateTime.now(), metaObject);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
//更新数据时,直接更新字段
|
||||
setFieldValByName("updated", LocalDateTime.now(), metaObject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.sl.transport.common.interceptor;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import com.itheima.auth.factory.AuthTemplateFactory;
|
||||
import com.itheima.auth.sdk.AuthTemplate;
|
||||
import com.sl.transport.common.annotation.NoAuthorization;
|
||||
import com.sl.transport.common.util.AuthTemplateThreadLocal;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Token拦截器
|
||||
* 用于将包含token的AuthTemplate实例存放到ThreadLocal的拦截器
|
||||
* 方便后续服务根据AuthTemplate实例访问权限系统
|
||||
* 顺序在用户信息拦截器之后
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class TokenInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
if (!(handler instanceof HandlerMethod)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||
if (handlerMethod.hasMethodAnnotation(NoAuthorization.class)) {
|
||||
//不需要校验,直接放行
|
||||
return true;
|
||||
}
|
||||
|
||||
// 从请求头获取token
|
||||
String token = request.getHeader("token");
|
||||
if (CharSequenceUtil.isEmpty(token)) {
|
||||
response.setStatus(403);
|
||||
return false;
|
||||
}
|
||||
|
||||
AuthTemplate authTemplate = AuthTemplateFactory.get(token);
|
||||
AuthTemplateThreadLocal.set(authTemplate);
|
||||
log.info("拦截器拦截到请求:{}", request.getRequestURI());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||
AuthTemplateThreadLocal.remove();
|
||||
log.info("请求结束:{}", request.getRequestURI());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.sl.transport.common.interceptor;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.sl.transport.common.util.UserThreadLocal;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 如果需要通过Feign将用户信息向下游微服务传递,需要在配置文件中设置:sl.feign.user = true
|
||||
*/
|
||||
@Component
|
||||
@ConditionalOnProperty(prefix = "sl.feign", value = "user")
|
||||
public class UserFeignRequestInterceptor implements RequestInterceptor {
|
||||
|
||||
@Override
|
||||
public void apply(RequestTemplate template) {
|
||||
//将userInfo放到feign请求头中,向下游的服务传递
|
||||
String userInfo = Base64.encode(JSONUtil.toJsonStr(UserThreadLocal.get()));
|
||||
template.header("userInfo", userInfo);
|
||||
template.header("X-Request-From", "sl-express-gateway");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.sl.transport.common.interceptor;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.sl.transport.common.annotation.NoAuthorization;
|
||||
import com.sl.transport.common.util.UserThreadLocal;
|
||||
import com.sl.transport.common.vo.AuthUserInfo;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 统一对请求的合法性进行校验,需要进行2个方面的校验,
|
||||
* 一、请求头中是否携带了X-Request-From,判断是否来源网关
|
||||
* 二、请求头中是否存在userInfo,如果不存在则说明是非法请求,响应403状态码
|
||||
* 如果是合法请求,将userInfo存储到ThreadLocal中
|
||||
*/
|
||||
@Component
|
||||
public class UserInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
if (!(handler instanceof HandlerMethod)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||
if (handlerMethod.hasMethodAnnotation(NoAuthorization.class)) {
|
||||
//不需要校验,直接放行
|
||||
return true;
|
||||
}
|
||||
|
||||
String from = request.getHeader("X-Request-From");
|
||||
if (!StrUtil.equals(from, "sl-express-gateway")) {
|
||||
response.setStatus(403);
|
||||
return false;
|
||||
}
|
||||
|
||||
String userInfo = request.getHeader("userInfo");
|
||||
if (Base64.isBase64(userInfo)) {
|
||||
userInfo = Base64.decodeStr(userInfo);
|
||||
}
|
||||
if (StrUtil.isEmpty(userInfo)) {
|
||||
response.setStatus(403);
|
||||
return false;
|
||||
}
|
||||
|
||||
UserThreadLocal.set(JSONUtil.toBean(userInfo, AuthUserInfo.class));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
UserThreadLocal.remove();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.sl.transport.common.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "spring.alioss")
|
||||
@Data
|
||||
public class AliOSSProperties {
|
||||
|
||||
private String endpoint;
|
||||
private String accessKeyId;
|
||||
private String accessKeySecret;
|
||||
private String bucketName;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.sl.transport.common.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "spring.eidverify")
|
||||
@Data
|
||||
public class RealNameVerifyProperties {
|
||||
|
||||
private String url;
|
||||
private String appCode;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.sl.transport.common.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @Description SwaggerConfigProperties配置类
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "sl.swagger")
|
||||
@ConditionalOnProperty(prefix = "sl.swagger",value = "package-path")
|
||||
public class SwaggerConfigProperties implements Serializable {
|
||||
|
||||
public String packagePath;
|
||||
|
||||
public String title;
|
||||
|
||||
public String description;
|
||||
|
||||
public String contactName;
|
||||
|
||||
public String contactUrl;
|
||||
|
||||
public String contactEmail;
|
||||
|
||||
public String version;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.sl.transport.common.service;
|
||||
|
||||
import com.aliyun.oss.ClientException;
|
||||
import com.aliyun.oss.OSS;
|
||||
import com.aliyun.oss.OSSClientBuilder;
|
||||
import com.aliyun.oss.OSSException;
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
import com.sl.transport.common.util.ObjectUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class AliOssService {
|
||||
|
||||
private String endpoint;
|
||||
private String accessKeyId;
|
||||
private String accessKeySecret;
|
||||
private String bucketName;
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @param file 源文件
|
||||
* @return 文件访问路径
|
||||
*/
|
||||
public String upload(MultipartFile file) {
|
||||
//获得原始文件名
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
//获得文件扩展名
|
||||
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
|
||||
String fileName = UUID.randomUUID() + extension;
|
||||
|
||||
// 创建OSSClient实例。
|
||||
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
|
||||
StringBuilder stringBuilder = new StringBuilder("https://");
|
||||
|
||||
try {
|
||||
// 创建PutObject请求。
|
||||
ossClient.putObject(bucketName, fileName, new ByteArrayInputStream(file.getBytes()));
|
||||
|
||||
//文件访问路径规则 https://BucketName.Endpoint/ObjectName
|
||||
stringBuilder
|
||||
.append(bucketName)
|
||||
.append(".")
|
||||
.append(endpoint)
|
||||
.append("/")
|
||||
.append(fileName);
|
||||
} catch (OSSException oe) {
|
||||
log.error("阿里OSS异常,Error Message:{}", oe.getErrorMessage());
|
||||
} catch (ClientException ce) {
|
||||
log.error("阿里OSS Client异常,Error Message:{}", ce.getMessage());
|
||||
} catch (IOException ie) {
|
||||
log.error("文件上传IO异常,Error Message:{}", ie.getMessage());
|
||||
} finally {
|
||||
if (ObjectUtil.isNotEmpty(ossClient)) {
|
||||
ossClient.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片上传
|
||||
*
|
||||
* @param file 图片文件
|
||||
* @return 文件访问路径
|
||||
*/
|
||||
public String uploadImage(MultipartFile file) {
|
||||
try {
|
||||
//校验是否为图片文件
|
||||
BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
|
||||
if (bufferedImage == null) {
|
||||
throw new SLException("上传图片大小不能超过5M,格式需为jpg、png、gif");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("文件上传IO异常,Error Message:{}", e.getMessage());
|
||||
}
|
||||
|
||||
//文件上传并获取访问路径
|
||||
return this.upload(file);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.sl.transport.common.service;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.sl.transport.common.enums.IdEnum;
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* id服务,用于生成自定义的id
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
@Service
|
||||
public class IdService {
|
||||
|
||||
@Value("${sl.id.leaf:}")
|
||||
private String leafUrl;
|
||||
|
||||
/**
|
||||
* 生成自定义id
|
||||
*
|
||||
* @param idEnum id配置
|
||||
* @return id值
|
||||
*/
|
||||
public String getId(IdEnum idEnum) {
|
||||
String idStr = this.doGet(idEnum);
|
||||
return idEnum.getPrefix() + idStr;
|
||||
}
|
||||
|
||||
private String doGet(IdEnum idEnum) {
|
||||
if (StrUtil.isEmpty(this.leafUrl)) {
|
||||
throw new SLException("生成id,sl.id.leaf配置不能为空.");
|
||||
}
|
||||
//访问leaf服务获取id
|
||||
String url = StrUtil.format("{}/api/{}/get/{}", this.leafUrl, idEnum.getType(), idEnum.getBiz());
|
||||
//设置超时时间为10s
|
||||
HttpResponse httpResponse = HttpRequest.get(url)
|
||||
.setReadTimeout(10000)
|
||||
.execute();
|
||||
if (httpResponse.isOk()) {
|
||||
return httpResponse.body();
|
||||
}
|
||||
throw new SLException(StrUtil.format("访问leaf服务出错,leafUrl = {}, idEnum = {}", this.leafUrl, idEnum));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.sl.transport.common.service;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.FormBody;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 温馨提示:
|
||||
* 1.解析结果时,先判断code
|
||||
* 2.出现'无记录'时,有以下几种原因
|
||||
* (1)现役军人、武警官兵、特殊部门人员及特殊级别官员;
|
||||
* (2)退役不到2年的军人和士兵(根据军衔、兵种不同,时间会有所不同,一般为2年);
|
||||
* (3)户口迁出,且没有在新的迁入地迁入;
|
||||
* (4)户口迁入新迁入地,当地公安系统未将迁移信息上报到公安部(上报时间地域不同而有所差异);
|
||||
* (5)更改姓名,当地公安系统未将更改信息上报到公安部(上报时间因地域不同而有所差异);
|
||||
* (6)移民;
|
||||
* (7)未更换二代身份证;
|
||||
* (8)死亡。
|
||||
* (9)身份证号确实不存在
|
||||
* {
|
||||
* "code": "0", //返回码,0:成功,非0:失败(详见错误码定义)
|
||||
* //当code=0时,再判断下面result中的res;当code!=0时,表示调用已失败,无需再继续
|
||||
* "message": "成功", //返回码说明
|
||||
* "result": {
|
||||
* "name": "冯天", //姓名
|
||||
* "idcard": "350301198011129422", //身份证号
|
||||
* "res": "1", //核验结果状态码,1 一致;2 不一致;3 无记录
|
||||
* "description": "一致", //核验结果状态描述
|
||||
* "sex": "男",
|
||||
* "birthday": "19940320",
|
||||
* "address": "江西省南昌市东湖区"
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class RealNameVerifyService {
|
||||
|
||||
private String url;
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 实名认证
|
||||
*
|
||||
* @param name 姓名
|
||||
* @param idCard 身份证号
|
||||
* @return 是否通过认证
|
||||
* @throws IOException io异常
|
||||
*/
|
||||
public boolean realNameVerify(String name, String idCard) throws IOException {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("idcard", idCard);
|
||||
params.put("name", name);
|
||||
|
||||
OkHttpClient client = new OkHttpClient.Builder().build();
|
||||
FormBody.Builder formbuilder = new FormBody.Builder();
|
||||
Iterator<String> it = params.keySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
String key = it.next();
|
||||
formbuilder.add(key, params.get(key));
|
||||
}
|
||||
FormBody body = formbuilder.build();
|
||||
Request request = new Request.Builder().url(url).addHeader("Authorization", "APPCODE " + appCode).post(body).build();
|
||||
Response response = client.newCall(request).execute();
|
||||
log.info("返回状态码" + response.code() + ",message:" + response.message());
|
||||
|
||||
if (ObjectUtil.notEqual(response.code(), 200)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String flag = (String) JSONUtil.parseObj(response.body().string()).getJSONObject("result").get("res");
|
||||
|
||||
return ObjectUtil.equal(flag, "1");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.sl.transport.common.util;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.Signature;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Slf4j
|
||||
public class AspectUtil {
|
||||
|
||||
/**
|
||||
* 获取被拦截方法对象
|
||||
* @param pjp {@link ProceedingJoinPoint}
|
||||
* @return {@link Method}
|
||||
*/
|
||||
public static Method getMethod(ProceedingJoinPoint pjp) {
|
||||
//获取参数的类型
|
||||
Signature sig = pjp.getSignature();
|
||||
if (sig instanceof MethodSignature) {
|
||||
MethodSignature methodSignature = (MethodSignature) sig;
|
||||
return methodSignature.getMethod();
|
||||
} else {
|
||||
throw new IllegalArgumentException("It's not method");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析SPEL表达式
|
||||
*
|
||||
* @param key key
|
||||
* @param method {@link Method}
|
||||
* @param args {@code Object[]}
|
||||
* @return key
|
||||
*/
|
||||
public static String parse(String key, Method method, Object[] args) {
|
||||
if (StringUtils.isNotBlank(key) && key.indexOf("#") > -1) {
|
||||
Pattern pattern = Pattern.compile("(\\#\\{([^\\}]*)\\})");
|
||||
Matcher matcher = pattern.matcher(key);
|
||||
List<String> keys = new ArrayList<>();
|
||||
while (matcher.find()) {
|
||||
keys.add(matcher.group());
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(keys)) {
|
||||
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
|
||||
String[] paraNameArr = u.getParameterNames(method);
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
for (int i = 0; i < paraNameArr.length; i++) {
|
||||
context.setVariable(paraNameArr[i], args[i]);
|
||||
}
|
||||
for (String tmp : keys) {
|
||||
key = key.replace(tmp, parser.parseExpression("#" + tmp.substring(2, tmp.length() - 1)).getValue(context, String.class));
|
||||
}
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求体
|
||||
*
|
||||
* @param pjp {@link ProceedingJoinPoint}
|
||||
* @return {@code Object}
|
||||
*/
|
||||
public static Object getBody(ProceedingJoinPoint pjp) {
|
||||
Object[] args = pjp.getArgs();
|
||||
Method method = getMethod(pjp);
|
||||
|
||||
if (ObjectUtil.isNotEmpty(args)) {
|
||||
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||
for (int count = 0; count < parameterAnnotations.length; count++) {
|
||||
for (Annotation annotation : parameterAnnotations[count]) {
|
||||
if (annotation instanceof RequestBody) {
|
||||
return args[count];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.sl.transport.common.util;
|
||||
|
||||
import com.itheima.auth.sdk.AuthTemplate;
|
||||
|
||||
/**
|
||||
* 包含token的权限系统client
|
||||
* 存储在ThreadLocal
|
||||
*/
|
||||
public class AuthTemplateThreadLocal {
|
||||
|
||||
private static final ThreadLocal<AuthTemplate> LOCAL = new ThreadLocal<>();
|
||||
|
||||
private AuthTemplateThreadLocal() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 将authTemplate放到ThreadLocal中
|
||||
*
|
||||
* @param authTemplate {@link AuthTemplate}
|
||||
*/
|
||||
public static void set(AuthTemplate authTemplate) {
|
||||
LOCAL.set(authTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ThreadLocal中获取authTemplate
|
||||
*/
|
||||
public static AuthTemplate get() {
|
||||
return LOCAL.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从当前线程中删除authTemplate
|
||||
*/
|
||||
public static void remove() {
|
||||
LOCAL.remove();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.sl.transport.common.util;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.sl.transport.common.handler.ConvertHandler;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
public class BeanUtil extends cn.hutool.core.bean.BeanUtil {
|
||||
/**
|
||||
* 对象或Map转Bean
|
||||
*
|
||||
* @param originObject 源对象或Map
|
||||
* @param entityClass 目标的Bean类型
|
||||
* @param convertHandler 特殊对象类型转换器,可传null,即不进行特殊处理
|
||||
* @return 目标对象
|
||||
*/
|
||||
public static <O, T> T toBean(O originObject, Class<T> entityClass, ConvertHandler<O, T> convertHandler) {
|
||||
T targetObject = cn.hutool.core.bean.BeanUtil.toBean(originObject, entityClass);
|
||||
//特殊类型转换
|
||||
if (ObjectUtil.isNotEmpty(targetObject) && ObjectUtil.isNotEmpty(convertHandler)) {
|
||||
convertHandler.map(originObject, targetObject);
|
||||
}
|
||||
return targetObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象或Map转Bean,忽略字段转换时发生的异常
|
||||
*
|
||||
* @param originObject 源对象或Map
|
||||
* @param entityClass 目标的Bean类型
|
||||
* @param ignoreError 是否忽略注入错误
|
||||
* @param convertHandler 特殊对象类型转换器,可传null,即不进行特殊处理
|
||||
* @return 目标对象
|
||||
*/
|
||||
public static <O, T> T toBeanIgnoreCase(O originObject, Class<T> entityClass, boolean ignoreError, ConvertHandler<O, T> convertHandler) {
|
||||
T targetObject = cn.hutool.core.bean.BeanUtil.toBeanIgnoreCase(originObject, entityClass, ignoreError);
|
||||
//特殊类型转换
|
||||
if (ObjectUtil.isNotEmpty(targetObject) && ObjectUtil.isNotEmpty(convertHandler)) {
|
||||
convertHandler.map(originObject, targetObject);
|
||||
}
|
||||
return targetObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象或Map转Bean,忽略字段转换时发生的异常
|
||||
*
|
||||
* @param originObject 源对象或Map
|
||||
* @param entityClass 目标的Bean类型
|
||||
* @param convertHandler 特殊对象类型转换器,可传null,即不进行特殊处理
|
||||
* @return 目标对象
|
||||
*/
|
||||
public static <O, T> T toBeanIgnoreError(O originObject, Class<T> entityClass, ConvertHandler<O, T> convertHandler) {
|
||||
T targetObject = cn.hutool.core.bean.BeanUtil.toBeanIgnoreError(originObject, entityClass);
|
||||
//特殊类型转换
|
||||
if (ObjectUtil.isNotEmpty(targetObject) && ObjectUtil.isNotEmpty(convertHandler)) {
|
||||
convertHandler.map(originObject, targetObject);
|
||||
}
|
||||
return targetObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制集合中的Bean属性
|
||||
*
|
||||
* @param originList 原Bean集合
|
||||
* @param targetType 目标Bean类型
|
||||
* @param convertHandler 特殊对象类型转换器,可传null,即不进行特殊处理
|
||||
* @return 复制后的List
|
||||
*/
|
||||
public static <O, T> List<T> copyToList(List<O> originList, Class<T> targetType, ConvertHandler<O, T> convertHandler) {
|
||||
List<T> targetList = cn.hutool.core.bean.BeanUtil.copyToList(originList, targetType);
|
||||
//特殊类型转换
|
||||
if (CollUtil.isNotEmpty(targetList) && ObjectUtil.isNotEmpty(convertHandler)) {
|
||||
for (int i = 0; i < originList.size(); i++) {
|
||||
convertHandler.map(originList.get(i), targetList.get(i));
|
||||
}
|
||||
}
|
||||
return targetList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为object设置默认值,对target中的基本类型进行默认值初始化,
|
||||
* 为null的对象不操作
|
||||
*
|
||||
* @param target 目标对象
|
||||
*/
|
||||
public static void setDefault(Object target) {
|
||||
if (ObjectUtil.isEmpty(target)) {
|
||||
return;
|
||||
}
|
||||
Class<?> clazz = target.getClass();
|
||||
Field[] declaredFields = clazz.getDeclaredFields();
|
||||
for (Field field : declaredFields) {
|
||||
setDefault(field, target);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void setDefault(Field field, Object target) {
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
try {
|
||||
Object value = field.get(target);
|
||||
if (ObjectUtil.isNotEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
String type = field.getGenericType().toString();
|
||||
Object defaultValue;
|
||||
switch (type) {
|
||||
case "class java.lang.String":
|
||||
case "class java.lang.Character": {
|
||||
defaultValue = "";
|
||||
break;
|
||||
}
|
||||
case "class java.lang.Double": {
|
||||
defaultValue = 0.0d;
|
||||
break;
|
||||
}
|
||||
case "class java.lang.Long": {
|
||||
defaultValue = 0L;
|
||||
break;
|
||||
}
|
||||
case "class java.lang.Short": {
|
||||
defaultValue = (short) 0;
|
||||
break;
|
||||
}
|
||||
case "class java.lang.Integer": {
|
||||
defaultValue = 0;
|
||||
break;
|
||||
}
|
||||
case "class java.lang.Float": {
|
||||
defaultValue = 0f;
|
||||
break;
|
||||
}
|
||||
case "class java.lang.Byte": {
|
||||
defaultValue = (byte) 0;
|
||||
break;
|
||||
}
|
||||
case "class java.math.BigDecimal": {
|
||||
defaultValue = BigDecimal.ZERO;
|
||||
break;
|
||||
}
|
||||
case "class java.lang.Boolean": {
|
||||
defaultValue = Boolean.FALSE;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
defaultValue = null;
|
||||
}
|
||||
|
||||
}
|
||||
ReflectionUtils.setField(field, target, defaultValue);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.sl.transport.common.util;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
* 扩展hutool的CoordinateUtil
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
public class CoordinateUtil extends cn.hutool.core.util.CoordinateUtil {
|
||||
|
||||
/**
|
||||
* 将字符串格式化成 Coordinate 对象
|
||||
*
|
||||
* @param coordinateStr 经度,纬度
|
||||
* @return Coordinate对象
|
||||
*/
|
||||
public static Coordinate format(String coordinateStr) {
|
||||
double[] ds = Convert.convert(double[].class, StrUtil.splitTrim(coordinateStr, ','));
|
||||
return new Coordinate(ds[0], ds[1]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package com.sl.transport.common.util;
|
||||
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
public class DateUtils {
|
||||
|
||||
public static final String DEFAULT_YEAR_FORMAT = "yyyy";
|
||||
public static final String DEFAULT_MONTH_FORMAT = "yyyy-MM";
|
||||
public static final String DEFAULT_MONTH_FORMAT_SLASH = "yyyy/MM";
|
||||
public static final String DEFAULT_MONTH_FORMAT_EN = "yyyy年MM月";
|
||||
public static final String DEFAULT_WEEK_FORMAT = "yyyy-ww";
|
||||
public static final String DEFAULT_WEEK_FORMAT_EN = "yyyy年ww周";
|
||||
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
||||
public static final String DEFAULT_DATE_FORMAT_EN = "yyyy年MM月dd日";
|
||||
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
|
||||
public static final String DEFAULT_TIME_WITHOUT_SECOND = "HH:mm";
|
||||
public static final String DEFAULT_TIME_WITHOUT_YEAR = "MM-dd HH:mm";
|
||||
public static final String DAY = "DAY";
|
||||
public static final String MONTH = "MONTH";
|
||||
public static final String WEEK = "WEEK";
|
||||
public static final long MAX_MONTH_DAY = 30L;
|
||||
public static final long MAX_3_MONTH_DAY = 90L;
|
||||
public static final long MAX_YEAR_DAY = 365L;
|
||||
|
||||
public static final String TIME_ZONE_8 = "GMT+8";
|
||||
|
||||
/**
|
||||
* 获取utc时间
|
||||
* @param localDateTime
|
||||
* @return
|
||||
*/
|
||||
public static LocalDateTime getUTCTime(LocalDateTime localDateTime) {
|
||||
ZoneId australia = ZoneId.of("Asia/Shanghai");
|
||||
ZonedDateTime dateAndTimeInSydney = ZonedDateTime.of(localDateTime, australia);
|
||||
ZonedDateTime utcDate = dateAndTimeInSydney.withZoneSameInstant(ZoneOffset.UTC);
|
||||
return utcDate.toLocalDateTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取utc时间
|
||||
* @param localDateTime
|
||||
* @return
|
||||
*/
|
||||
public static LocalDateTime getAsiaTime(LocalDateTime localDateTime) {
|
||||
ZoneId australia = ZoneId.of("Asia/Shanghai");
|
||||
ZonedDateTime dateAndTimeInSydney = ZonedDateTime.of(localDateTime, ZoneOffset.UTC);
|
||||
ZonedDateTime utcDate = dateAndTimeInSydney.withZoneSameInstant(australia);
|
||||
return utcDate.toLocalDateTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据月份计算月份的开始时间
|
||||
*
|
||||
* @param month 格式yyyy-MM
|
||||
* @return
|
||||
*/
|
||||
public static LocalDateTime getMonthStartTime(String month) {
|
||||
LocalDateTime dateTime = LocalDateTimeUtil.parse(month, DEFAULT_MONTH_FORMAT);
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据月份计算月份的结束时间
|
||||
*
|
||||
* @param month 格式yyyy-MM
|
||||
* @return
|
||||
*/
|
||||
public static LocalDateTime getMonthEndTime(String month) {
|
||||
if(StringUtils.isEmpty(month)){
|
||||
return null;
|
||||
}
|
||||
String[] dates = month.split("-");
|
||||
int year = Integer.parseInt(dates[0]);
|
||||
int nextMonth = Integer.parseInt(dates[1]) + 1;
|
||||
if (Integer.parseInt(dates[1]) == 12) {
|
||||
// 12月特殊处理
|
||||
year = Integer.parseInt(dates[0]) + 1;
|
||||
nextMonth = 1;
|
||||
}
|
||||
LocalDateTime of = LocalDateTime.of(year, nextMonth, 1, 0, 0);
|
||||
return of.minusSeconds(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定时间当天的开始时间
|
||||
*
|
||||
* @param localDateTime 指定时间
|
||||
* @return 指定时间的当天开始时间
|
||||
*/
|
||||
public static LocalDateTime getStartTime(LocalDateTime localDateTime){
|
||||
if(localDateTime == null){
|
||||
return null;
|
||||
}
|
||||
return LocalDateTime.of(localDateTime.getYear(), localDateTime.getMonth(), localDateTime.getDayOfMonth(), 0,0);
|
||||
}
|
||||
|
||||
public static int getMonthNumber(LocalDateTime localDateTime) {
|
||||
int year = localDateTime.getYear();
|
||||
int month = localDateTime.getMonth().getValue();
|
||||
if(month == 12) {
|
||||
return LocalDateTime.of(year + 1, 1, 1,
|
||||
0, 0, 0).plusHours(-1L).getDayOfMonth();
|
||||
}else {
|
||||
return LocalDateTime.of(year, month + 1, 1, 0, 0, 0).plusHours(-1L).getDayOfMonth();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间加上x分钟
|
||||
*
|
||||
* @param date
|
||||
* @param minutes
|
||||
* @return
|
||||
*/
|
||||
public static Date plusMinutes(Date date, int minutes) {
|
||||
return Date.from(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().plusMinutes(minutes).atZone(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间加上x秒
|
||||
*
|
||||
* @param date
|
||||
* @param seconds
|
||||
* @return
|
||||
*/
|
||||
public static Date plusSeconds(Date date, int seconds) {
|
||||
return Date.from(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().plusSeconds(seconds).atZone(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间减去x分钟
|
||||
*
|
||||
* @param date
|
||||
* @param minutes
|
||||
* @return
|
||||
*/
|
||||
public static Date minusMinutes(Date date, int minutes) {
|
||||
return Date.from(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().minusMinutes(minutes).atZone(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间减去x秒
|
||||
*
|
||||
* @param date
|
||||
* @param seconds
|
||||
* @return
|
||||
*/
|
||||
public static Date minusSeconds(Date date, int seconds) {
|
||||
return Date.from(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().minusSeconds(seconds).atZone(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间减去x天
|
||||
*
|
||||
* @param date
|
||||
* @param days
|
||||
* @return
|
||||
*/
|
||||
public static Date minusDays(Date date, int days) {
|
||||
return Date.from(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().minusDays(days).atZone(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间增加x天
|
||||
*
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public static Date plusDays(Date date, int days) {
|
||||
return Date.from(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().plusDays(days).atZone(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间增加x天
|
||||
*
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public static LocalDateTime plusDays(LocalDateTime date, int days) {
|
||||
return date.plusDays(days);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.sl.transport.common.util;
|
||||
|
||||
import cn.hutool.core.date.DateField;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.crypto.asymmetric.RSA;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.JwsHeader;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* jwt工具类,提供生成token与校验token的方法,采用RSA非对称加密
|
||||
*/
|
||||
@Slf4j
|
||||
public class JwtUtils {
|
||||
|
||||
/**
|
||||
* 生成token(RSA非对称加密)
|
||||
*
|
||||
* @param claims token中存储的数据,请勿传入敏感数据
|
||||
* @param privateKeyStr RSA私钥字符串
|
||||
* @param dateOffset 过期时间,单位:小时
|
||||
* @return token字符串
|
||||
*/
|
||||
public static String createToken(Map<String, Object> claims, String privateKeyStr, int dateOffset) {
|
||||
return createToken(claims, privateKeyStr, dateOffset, DateField.HOUR_OF_DAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成token(RSA非对称加密)
|
||||
*
|
||||
* @param claims token中存储的数据,请勿传入敏感数据
|
||||
* @param privateKeyStr RSA私钥字符串
|
||||
* @param dateOffset 过期时间
|
||||
* @param dateField 过期时间的单位
|
||||
* @return token字符串
|
||||
*/
|
||||
public static String createToken(Map<String, Object> claims, String privateKeyStr, int dateOffset, DateField dateField) {
|
||||
RSA rsa = new RSA(privateKeyStr, null);
|
||||
|
||||
Map<String, Object> header = MapUtil.<String, Object>builder()
|
||||
.put(JwsHeader.TYPE, JwsHeader.JWT_TYPE)
|
||||
.put(JwsHeader.ALGORITHM, SignatureAlgorithm.RS256.getValue()).build();
|
||||
|
||||
// 生成token
|
||||
return Jwts.builder()
|
||||
.setHeader(header) //header,可省略
|
||||
.setClaims(claims) //payload,存放数据的位置,不能放置敏感数据,如:密码、手机号等
|
||||
.signWith(SignatureAlgorithm.RS256, rsa.getPrivateKey()) //设置签名的加密算法和密钥
|
||||
.setExpiration(DateUtil.offset(new Date(), dateField, dateOffset)) //设置过期时间
|
||||
.compact();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验token
|
||||
*
|
||||
* @param token token字符串
|
||||
* @param publicKeyStr RSA公钥字符串
|
||||
* @return token解密数据
|
||||
*/
|
||||
public static Map<String, Object> checkToken(String token, String publicKeyStr) {
|
||||
RSA rsa = new RSA(null, publicKeyStr);
|
||||
try {
|
||||
// 通过token解析数据
|
||||
Map<String, Object> body = Jwts.parser()
|
||||
.setSigningKey(rsa.getPublicKey()) //设置校验token签名的密钥
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
return body;
|
||||
} catch (ExpiredJwtException e) {
|
||||
// System.out.println("token已经过期!");
|
||||
} catch (Exception e) {
|
||||
log.error("token非法传入,token = {}", token, e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.sl.transport.common.util;
|
||||
|
||||
/**
|
||||
* 经纬度位置距离计算工具类
|
||||
*/
|
||||
public class LocationUtils {
|
||||
private LocationUtils(){}
|
||||
/**
|
||||
* 赤道半径
|
||||
*/
|
||||
private static final double EARTH_RADIUS = 6378.137;
|
||||
|
||||
private static double rad(double d) {
|
||||
return d * Math.PI / 180.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description : 通过经纬度获取距离(单位:米)
|
||||
* Group :
|
||||
*
|
||||
* @param originLon 出发点经度
|
||||
* @param originLat 出发点纬度
|
||||
* @param destinationLon 目的地经度
|
||||
* @param destinationLat 目的地纬度
|
||||
* @return double 距离
|
||||
*/
|
||||
public static double getDistance(Double originLon, Double originLat, Double destinationLon, Double destinationLat) {
|
||||
double radLat1 = rad(originLat);
|
||||
double radLat2 = rad(destinationLat);
|
||||
double a = radLat1 - radLat2;
|
||||
double b = rad(originLon) - rad(destinationLon);
|
||||
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
|
||||
+ Math.cos(radLat1) * Math.cos(radLat2)
|
||||
* Math.pow(Math.sin(b / 2), 2)));
|
||||
s = s * EARTH_RADIUS;
|
||||
// 保留两位小数
|
||||
s = Math.round(s * 100d) / 100d;
|
||||
s = s * 1000;
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description : 通过经纬度获取距离(单位:米)
|
||||
* Group :
|
||||
*
|
||||
* @param originLon 出发点经度
|
||||
* @param originLat 出发点纬度
|
||||
* @param location 目的地经度纬度,格式:经度,纬度
|
||||
* @return double 距离
|
||||
*/
|
||||
public static double getDistance(Double originLon, Double originLat, String location) {
|
||||
String[] locationInfos = location.split(",");
|
||||
return getDistance(originLon, originLat, Double.parseDouble(locationInfos[0]), Double.parseDouble(locationInfos[1]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.sl.transport.common.util;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
|
||||
/**
|
||||
* 扩展hutool中的方法
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
public class ObjectUtil extends cn.hutool.core.util.ObjectUtil {
|
||||
|
||||
/**
|
||||
* 给定对象是否与提供的中任一对象相同,相同则返回{@code true},没有相同的返回{@code false}<br>
|
||||
* 如果参与比对的对象列表为空,返回{@code false}
|
||||
*
|
||||
* @param obj1 给定需要检查的对象
|
||||
* @param objs 需要参与比对的对象列表
|
||||
* @return 是否相同
|
||||
*/
|
||||
public static boolean equalsAny(Object obj1, Object... objs) {
|
||||
if (ArrayUtil.isEmpty(objs)) {
|
||||
return false;
|
||||
}
|
||||
for (Object obj : objs) {
|
||||
if (cn.hutool.core.util.ObjectUtil.equal(obj1, obj)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
package com.sl.transport.common.util;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
import com.sl.transport.common.handler.ConvertHandler;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 分页结果包装
|
||||
*
|
||||
* @author itcast
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "分页数据消息体", description = "分页数据统一对象")
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@NoArgsConstructor
|
||||
public class PageResponse<T> {
|
||||
|
||||
@ApiModelProperty(value = "总条目数", required = true)
|
||||
private Long counts = 0L;
|
||||
|
||||
@ApiModelProperty(value = "页尺寸", required = true)
|
||||
private Integer pageSize = 0;
|
||||
|
||||
@ApiModelProperty(value = "总页数", required = true)
|
||||
private Long pages = 0L;
|
||||
|
||||
@ApiModelProperty(value = "页码", required = true)
|
||||
private Integer page = 0;
|
||||
|
||||
@ApiModelProperty(value = "数据列表", required = true)
|
||||
private List<T> items = Collections.EMPTY_LIST;
|
||||
|
||||
|
||||
/**
|
||||
* 通过mybatis-plus的分页对象构造对象,不封装 items 属性
|
||||
*
|
||||
* @param page 分页对象
|
||||
*/
|
||||
public PageResponse(IPage<?> page) {
|
||||
this.page = Convert.toInt(page.getCurrent());
|
||||
this.counts = page.getTotal();
|
||||
this.pageSize = Convert.toInt(page.getSize());
|
||||
this.pages = page.getPages();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过mybatis-plus的分页对象构造对象,封装 items 属性
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param clazz 指定items 属性的类型
|
||||
*/
|
||||
public PageResponse(IPage<?> page, Class<T> clazz) {
|
||||
this.page = Convert.toInt(page.getCurrent());
|
||||
this.counts = page.getTotal();
|
||||
this.pageSize = Convert.toInt(page.getSize());
|
||||
this.pages = page.getPages();
|
||||
this.items = BeanUtil.copyToList(page.getRecords(), clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回一个分页对象实例
|
||||
*
|
||||
* @return 分页数据对象
|
||||
*/
|
||||
public static <T> PageResponse<T> getInstance() {
|
||||
return PageResponse.<T>builder().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Page{@link IPage}对象封装为PageResponse,不封装 items 属性
|
||||
*
|
||||
* @param page 源分页对象
|
||||
* @return 目标分页数据对象
|
||||
*/
|
||||
public static <T> PageResponse<T> of(IPage<?> page) {
|
||||
//封装分页数据
|
||||
return PageResponse.<T>builder()
|
||||
.page(Convert.toInt(page.getCurrent()))
|
||||
.pageSize(Convert.toInt(page.getSize()))
|
||||
.pages(page.getPages())
|
||||
.counts(page.getTotal())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Page{@link IPage}对象封装为PageResponse,
|
||||
* 并将Page中的Records转换为指定类型封装为items
|
||||
*
|
||||
* @param page 源分页对象
|
||||
* @return 目标分页数据对象
|
||||
*/
|
||||
public static <T> PageResponse<T> of(IPage<?> page, Class<T> clazz) {
|
||||
return of(page, clazz, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Page{@link IPage}对象封装为PageResponse,
|
||||
* 并将Page中的Records转换为指定类型封装为items
|
||||
*
|
||||
* @param page 源分页对象
|
||||
* @param convertHandler 特殊对象类型转换器,可传null,即不进行特殊处理
|
||||
* @return 目标分页数据对象
|
||||
*/
|
||||
public static <O, T> PageResponse<T> of(IPage<O> page, Class<T> clazz, ConvertHandler<O, T> convertHandler) {
|
||||
//封装分页数据
|
||||
return PageResponse.<T>builder()
|
||||
.page(Convert.toInt(page.getCurrent()))
|
||||
.pageSize(Convert.toInt(page.getSize()))
|
||||
.pages(page.getPages())
|
||||
.counts(page.getTotal())
|
||||
.items(BeanUtil.copyToList(page.getRecords(), clazz, convertHandler))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对items进行类型转换
|
||||
*
|
||||
* @param origin 源分页数据对象
|
||||
* @param clazz 指定items 属性的类型,不能为null
|
||||
* @return 目标分页数据对象
|
||||
*/
|
||||
public static <O, T> PageResponse<T> of(PageResponse<O> origin, Class<T> clazz) {
|
||||
return of(origin, clazz, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对items进行类型转换
|
||||
*
|
||||
* @param origin 源分页数据对象
|
||||
* @param clazz 指定items 属性的类型,不能为null
|
||||
* @param convertHandler 特殊对象类型转换器,可传null,即不进行特殊处理
|
||||
* @return 目标分页数据对象
|
||||
*/
|
||||
public static <O, T> PageResponse<T> of(PageResponse<O> origin, Class<T> clazz, ConvertHandler<O, T> convertHandler) {
|
||||
//断言目标转换类型不为null
|
||||
if (null == clazz) {
|
||||
throw new SLException("目标转换类型不能为null!");
|
||||
}
|
||||
|
||||
//复制除items外的属性
|
||||
PageResponse<T> target = PageResponse.getInstance();
|
||||
BeanUtil.copyProperties(origin, target, "items");
|
||||
|
||||
//items为空,直接返回
|
||||
if (CollUtil.isEmpty(origin.getItems())) {
|
||||
return target;
|
||||
}
|
||||
|
||||
//对items进行类型转换
|
||||
List<T> targetList = BeanUtil.copyToList(origin.getItems(), clazz, convertHandler);
|
||||
target.setItems(targetList);
|
||||
|
||||
//封装分页数据
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* List{@link List}封装为分页数据对象
|
||||
*
|
||||
* @param items item数据
|
||||
* @param page 页码,可不传,数据不为空时默认为1
|
||||
* @param pageSize 页尺寸,可不传,数据不为空时默认为1
|
||||
* @param pages 页尺寸,可不传,数据不为空时默认为1
|
||||
* @param counts 总条目数,可不传,数据不为空时默认为1
|
||||
* @return 目标分页数据对象
|
||||
*/
|
||||
public static <T> PageResponse<T> of(List<T> items, Integer page, Integer pageSize, Long pages, Long counts) {
|
||||
//封装分页数据
|
||||
PageResponse<T> pageResponse = PageResponse.<T>builder()
|
||||
.page(Optional.ofNullable(page).orElse(1))
|
||||
.pageSize(Optional.ofNullable(pageSize).orElse(1))
|
||||
.pages(Optional.ofNullable(pages).orElse(1L))
|
||||
.counts(Optional.ofNullable(counts).orElse(1L))
|
||||
.build();
|
||||
|
||||
if (CollUtil.isEmpty(items)) {
|
||||
return pageResponse;
|
||||
}
|
||||
|
||||
pageResponse.setItems(items);
|
||||
return pageResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* List{@link List}封装为分页数据对象
|
||||
* 数据不为空时,page、pageSize、pages、counts均默认为1
|
||||
*
|
||||
* @param items item数据
|
||||
* @return 目标分页数据对象
|
||||
*/
|
||||
public static <T> PageResponse<T> of(List<T> items) {
|
||||
return of(items, null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回包含任意数量元素的分页对象
|
||||
* 数据不为空时,page、pageSize、pages、counts均默认为1
|
||||
*
|
||||
* @param elements items元素
|
||||
* @return 目标分页数据对象
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static <E> PageResponse<E> of(E... elements) {
|
||||
return of(List.of(elements));
|
||||
}
|
||||
|
||||
/**
|
||||
* 对items进行类型转换
|
||||
*
|
||||
* @param origin 源分页数据对象
|
||||
* @param function 自定义函数
|
||||
* @return 目标分页数据对象
|
||||
*/
|
||||
public static <O, T> PageResponse<T> of(PageResponse<O> origin, Function<List<O>, List<T>> function) {
|
||||
List<T> orderVOList = function.apply(origin.getItems());
|
||||
return PageResponse.of(orderVOList, origin.getPage(), origin.getPageSize(), origin.getPages(), origin.counts);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.sl.transport.common.util;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
/**
|
||||
* ResponseEntity 响应工具类
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
public class ResponseEntityUtils {
|
||||
|
||||
public static ResponseEntity<Void> created() {
|
||||
return ResponseEntity.status(HttpStatus.CREATED).build();
|
||||
}
|
||||
|
||||
public static ResponseEntity<Void> ok() {
|
||||
return ResponseEntity.ok(null);
|
||||
}
|
||||
|
||||
public static <T> ResponseEntity<T> ok(T t) {
|
||||
return ResponseEntity.ok(t);
|
||||
}
|
||||
|
||||
public static ResponseEntity<Void> error() {
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.sl.transport.common.util;
|
||||
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
import com.sl.transport.common.vo.AuthUserInfo;
|
||||
|
||||
public class UserThreadLocal {
|
||||
|
||||
private static final ThreadLocal<AuthUserInfo> LOCAL = new ThreadLocal<>();
|
||||
|
||||
private UserThreadLocal() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 将authUserInfo放到ThreadLocal中
|
||||
*
|
||||
* @param authUserInfo {@link AuthUserInfo}
|
||||
*/
|
||||
public static void set(AuthUserInfo authUserInfo) {
|
||||
LOCAL.set(authUserInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ThreadLocal中获取authUserInfo
|
||||
*/
|
||||
public static AuthUserInfo get() {
|
||||
return LOCAL.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从当前线程中删除authUserInfo
|
||||
*/
|
||||
public static void remove() {
|
||||
LOCAL.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从当前线程中获取用户id
|
||||
* @return 用户id
|
||||
*/
|
||||
public static Long getUserId() {
|
||||
AuthUserInfo userInfo = LOCAL.get();
|
||||
if (userInfo == null || userInfo.getUserId() == null) {
|
||||
throw new SLException("token异常");
|
||||
}
|
||||
return userInfo.getUserId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.sl.transport.common.vo;
|
||||
|
||||
import cn.hutool.core.annotation.Alias;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class AuthUserInfo extends BaseMsg{
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
@Alias("sub")
|
||||
private Long userId;
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String account;
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 机构id
|
||||
*/
|
||||
@Alias("orgid")
|
||||
private Long orgId;
|
||||
/**
|
||||
* 岗位
|
||||
*/
|
||||
@Alias("stationid")
|
||||
private Long stationId;
|
||||
|
||||
/**
|
||||
* 是否为管理员
|
||||
*/
|
||||
private Boolean administrator;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.sl.transport.common.vo;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BaseMsg {
|
||||
|
||||
/**
|
||||
* 扩展信息
|
||||
*/
|
||||
private String info;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Long created;
|
||||
|
||||
public String toJson() {
|
||||
return JSONUtil.toJsonStr(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.sl.transport.common.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* 快递员消息
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CourierMsg extends BaseMsg {
|
||||
|
||||
/**
|
||||
* 订单id
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 快递员id
|
||||
*/
|
||||
private Long courierId;
|
||||
|
||||
/**
|
||||
* 快递员姓名
|
||||
*/
|
||||
private String courierName;
|
||||
|
||||
/**
|
||||
* 快递员手机号
|
||||
*/
|
||||
private String courierMobile;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.sl.transport.common.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 生成快递员取派件任务消息体
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CourierTaskMsg extends BaseMsg{
|
||||
|
||||
/**
|
||||
* 快递员id
|
||||
*/
|
||||
private Long courierId;
|
||||
|
||||
/**
|
||||
* 网点id
|
||||
*/
|
||||
private Long agencyId;
|
||||
|
||||
/**
|
||||
* 任务类型,1为取件任务,2为派件任务
|
||||
*/
|
||||
private Integer taskType;
|
||||
|
||||
/**
|
||||
* 订单id
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 订单备注
|
||||
*/
|
||||
private String mark;
|
||||
|
||||
/**
|
||||
* 上门时间,用户选择13~14点上门,该值记录的是14点
|
||||
*/
|
||||
private LocalDateTime estimatedEndTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.sl.transport.common.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 订单消息
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class OrderMsg extends BaseMsg{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long orderId; //订单ID
|
||||
|
||||
/**
|
||||
* 任务类型,1为取件,2为派件
|
||||
*/
|
||||
private Integer taskType;
|
||||
|
||||
/**
|
||||
* 当前所在网点
|
||||
*/
|
||||
private Long agencyId;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String mark;
|
||||
|
||||
/**
|
||||
* 上门时间,用户选择13~14点上门,该值记录的是14点
|
||||
*/
|
||||
private LocalDateTime estimatedEndTime;
|
||||
|
||||
private Double longitude;
|
||||
|
||||
private Double latitude;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.sl.transport.common.vo;
|
||||
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 通用返回结果,服务端响应的数据最终都会封装成此对象
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
@Data
|
||||
public class R<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -4326147203336606257L;
|
||||
|
||||
@ApiModelProperty(value = "状态编码:200-成功,非200 -> 失败", required = true)
|
||||
private Integer code;
|
||||
@ApiModelProperty(value = "提示消息", required = true)
|
||||
private String msg;
|
||||
@ApiModelProperty(value = "响应数据", required = true)
|
||||
private T data; //数据
|
||||
|
||||
public static <T> R<T> success() {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
public static <T> R<T> success(T object) {
|
||||
R<T> r = new R<T>();
|
||||
r.data = object;
|
||||
r.code = 200;
|
||||
r.msg = "ok";
|
||||
return r;
|
||||
}
|
||||
|
||||
public static <T> R<T> error(String msg) {
|
||||
R r = new R();
|
||||
r.msg = msg;
|
||||
r.code = 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
public static <T> R<T> error(T object, String msg) {
|
||||
R r = new R();
|
||||
r.msg = msg;
|
||||
r.code = 1;
|
||||
r.data = object;
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@JsonIgnore
|
||||
public Boolean isSuccess() {
|
||||
return NumberUtil.equals(this.code, 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.sl.transport.common.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* 交易状态消息
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TradeStatusMsg extends BaseMsg {
|
||||
|
||||
/**
|
||||
* 交易单号
|
||||
*/
|
||||
private Long tradingOrderNo;
|
||||
|
||||
/**
|
||||
* 订单号
|
||||
*/
|
||||
private Long productOrderNo;
|
||||
|
||||
/**
|
||||
* 退款单号
|
||||
*/
|
||||
private Long refundNo;
|
||||
|
||||
/**
|
||||
* 支付/退款 状态名称
|
||||
*/
|
||||
private String statusName;
|
||||
|
||||
/**
|
||||
* 支付/退款 状态编码
|
||||
*/
|
||||
private Integer statusCode;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.sl.transport.common.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 运单跟踪消息
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TransportInfoMsg extends BaseMsg implements Serializable {
|
||||
private static final long serialVersionUID = 2386845612549524970L;
|
||||
|
||||
/**
|
||||
* 机构id
|
||||
*/
|
||||
@ApiModelProperty("机构id")
|
||||
private Long organId;
|
||||
|
||||
/**
|
||||
* 运单id
|
||||
*/
|
||||
@ApiModelProperty("运单id")
|
||||
private String transportOrderId;
|
||||
|
||||
/**
|
||||
* 消息状态
|
||||
*/
|
||||
@ApiModelProperty("消息状态")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 消息详情
|
||||
*/
|
||||
@ApiModelProperty("消息详情")
|
||||
private String info;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.sl.transport.common.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* 运单消息
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TransportOrderMsg extends BaseMsg {
|
||||
|
||||
/**
|
||||
* 运单号
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 订单id
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.sl.transport.common.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 运单状态更新消息
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TransportOrderStatusMsg extends BaseMsg {
|
||||
|
||||
/**
|
||||
* 运单号列表
|
||||
*/
|
||||
private List<String> idList;
|
||||
|
||||
/**
|
||||
* 状态名称
|
||||
*/
|
||||
private String statusName;
|
||||
|
||||
/**
|
||||
* 状态编码
|
||||
*/
|
||||
private Integer statusCode;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user