clazz) {
+ T t = BeanUtils.instantiateClass(clazz);
+ t.setId(id);
+ BeanUtils.copyProperties(this, t);
+ return t;
+ }
+}
diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/entity/form/BaseQueryForm.java b/common/web/src/main/java/com/springboot/cloud/common/web/entity/form/BaseQueryForm.java
new file mode 100644
index 0000000..3bdaa5d
--- /dev/null
+++ b/common/web/src/main/java/com/springboot/cloud/common/web/entity/form/BaseQueryForm.java
@@ -0,0 +1,44 @@
+package com.springboot.cloud.common.web.entity.form;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.springboot.cloud.common.web.entity.param.BaseParam;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+
+@ApiModel
+@Slf4j
+@Data
+public class BaseQueryForm extends BaseForm {
+ /**
+ * 分页查询的参数,当前页数
+ */
+ private long current = 1;
+ /**
+ * 分页查询的参数,当前页面每页显示的数量
+ */
+ private long size = 10;
+
+ /**
+ * Form转化为Param
+ *
+ * @param clazz
+ * @return
+ */
+ public P toParam(Class
clazz) {
+ P p = BeanUtils.instantiateClass(clazz);
+ BeanUtils.copyProperties(this, p);
+ return p;
+ }
+
+ /**
+ * 从form中获取page参数,用于分页查询参数
+ *
+ * @return
+ */
+ public Page getPage() {
+ return new Page(this.getCurrent(), this.getSize());
+ }
+
+}
diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/entity/param/BaseParam.java b/common/web/src/main/java/com/springboot/cloud/common/web/entity/param/BaseParam.java
new file mode 100644
index 0000000..a192322
--- /dev/null
+++ b/common/web/src/main/java/com/springboot/cloud/common/web/entity/param/BaseParam.java
@@ -0,0 +1,21 @@
+package com.springboot.cloud.common.web.entity.param;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.springboot.cloud.common.web.entity.po.BasePo;
+import lombok.Data;
+
+import java.util.Date;
+
+
+@Data
+public class BaseParam {
+ private Date createdTimeStart;
+ private Date createdTimeEnd;
+
+ public QueryWrapper build() {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.ge(null != this.createdTimeStart, "created_time", this.createdTimeStart)
+ .le(null != this.createdTimeEnd, "created_time", this.createdTimeEnd);
+ return queryWrapper;
+ }
+}
diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/entity/po/BasePo.java b/common/web/src/main/java/com/springboot/cloud/common/web/entity/po/BasePo.java
new file mode 100644
index 0000000..c21f2b4
--- /dev/null
+++ b/common/web/src/main/java/com/springboot/cloud/common/web/entity/po/BasePo.java
@@ -0,0 +1,29 @@
+package com.springboot.cloud.common.web.entity.po;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class BasePo implements Serializable {
+ public final static String DEFAULT_USERNAME = "system";
+ @TableId(type = IdType.ID_WORKER_STR)
+ private String id;
+
+ @TableField(fill = FieldFill.INSERT)
+ private String createdBy;
+
+ @TableField(fill = FieldFill.INSERT)
+ private Date createdTime;
+
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ private String updatedBy;
+
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ private Date updatedTime;
+}
diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/entity/vo/BaseVo.java b/common/web/src/main/java/com/springboot/cloud/common/web/entity/vo/BaseVo.java
new file mode 100644
index 0000000..226933f
--- /dev/null
+++ b/common/web/src/main/java/com/springboot/cloud/common/web/entity/vo/BaseVo.java
@@ -0,0 +1,13 @@
+package com.springboot.cloud.common.web.entity.vo;
+
+import com.springboot.cloud.common.web.entity.po.BasePo;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@NoArgsConstructor
+public class BaseVo implements Serializable {
+ private String id;
+}
diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/exception/DefaultGlobalExceptionHandlerAdvice.java b/common/web/src/main/java/com/springboot/cloud/common/web/exception/DefaultGlobalExceptionHandlerAdvice.java
new file mode 100644
index 0000000..1184e36
--- /dev/null
+++ b/common/web/src/main/java/com/springboot/cloud/common/web/exception/DefaultGlobalExceptionHandlerAdvice.java
@@ -0,0 +1,59 @@
+package com.springboot.cloud.common.web.exception;
+
+import com.springboot.cloud.common.core.entity.vo.Result;
+import com.springboot.cloud.common.core.exception.BaseException;
+import com.springboot.cloud.common.core.exception.SystemErrorType;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.multipart.MultipartException;
+
+@Slf4j
+public class DefaultGlobalExceptionHandlerAdvice {
+
+ @ExceptionHandler(value = {MissingServletRequestParameterException.class})
+ public Result missingServletRequestParameterException(MissingServletRequestParameterException ex) {
+ log.error("missing servlet request parameter exception:{}", ex.getMessage());
+ return Result.fail(SystemErrorType.ARGUMENT_NOT_VALID);
+ }
+
+ @ExceptionHandler(value = {MultipartException.class})
+ public Result uploadFileLimitException(MultipartException ex) {
+ log.error("upload file size limit:{}", ex.getMessage());
+ return Result.fail(SystemErrorType.UPLOAD_FILE_SIZE_LIMIT);
+ }
+
+ @ExceptionHandler(value = {MethodArgumentNotValidException.class})
+ public Result serviceException(MethodArgumentNotValidException ex) {
+ log.error("service exception:{}", ex.getMessage());
+ return Result.fail(SystemErrorType.ARGUMENT_NOT_VALID, ex.getBindingResult().getFieldError().getDefaultMessage());
+ }
+
+ @ExceptionHandler(value = {DuplicateKeyException.class})
+ public Result duplicateKeyException(DuplicateKeyException ex) {
+ log.error("primary key duplication exception:{}", ex.getMessage());
+ return Result.fail(SystemErrorType.DUPLICATE_PRIMARY_KEY);
+ }
+
+ @ExceptionHandler(value = {BaseException.class})
+ public Result baseException(BaseException ex) {
+ log.error("base exception:{}", ex.getMessage());
+ return Result.fail(ex.getErrorType());
+ }
+
+ @ExceptionHandler(value = {Exception.class})
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ public Result exception() {
+ return Result.fail();
+ }
+
+ @ExceptionHandler(value = {Throwable.class})
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ public Result throwable() {
+ return Result.fail();
+ }
+}
\ No newline at end of file
diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/handler/PoMetaObjectHandler.java b/common/web/src/main/java/com/springboot/cloud/common/web/handler/PoMetaObjectHandler.java
new file mode 100644
index 0000000..eec4c41
--- /dev/null
+++ b/common/web/src/main/java/com/springboot/cloud/common/web/handler/PoMetaObjectHandler.java
@@ -0,0 +1,36 @@
+package com.springboot.cloud.common.web.handler;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import com.springboot.cloud.common.core.util.UserContextHolder;
+import com.springboot.cloud.common.web.entity.po.BasePo;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.apache.ibatis.reflection.MetaObject;
+
+import java.time.ZonedDateTime;
+import java.util.Date;
+
+@Slf4j
+public class PoMetaObjectHandler implements MetaObjectHandler {
+ /**
+ * 获取当前访问用户,为空返回默认system
+ *
+ * @return
+ */
+ private String getCurrentUsername() {
+ return StringUtils.defaultIfBlank(UserContextHolder.getInstance().getUsername(), BasePo.DEFAULT_USERNAME);
+ }
+
+ @Override
+ public void insertFill(MetaObject metaObject) {
+ this.setInsertFieldValByName("createdBy", getCurrentUsername(), metaObject);
+ this.setInsertFieldValByName("createdTime", Date.from(ZonedDateTime.now().toInstant()), metaObject);
+ this.updateFill(metaObject);
+ }
+
+ @Override
+ public void updateFill(MetaObject metaObject) {
+ this.setUpdateFieldValByName("updatedBy", getCurrentUsername(), metaObject);
+ this.setUpdateFieldValByName("updatedTime", Date.from(ZonedDateTime.now().toInstant()), metaObject);
+ }
+}
\ No newline at end of file
diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/interceptor/FeignBasicAuthRequestInterceptor.java b/common/web/src/main/java/com/springboot/cloud/common/web/interceptor/FeignBasicAuthRequestInterceptor.java
new file mode 100644
index 0000000..e8b3f47
--- /dev/null
+++ b/common/web/src/main/java/com/springboot/cloud/common/web/interceptor/FeignBasicAuthRequestInterceptor.java
@@ -0,0 +1,46 @@
+package com.springboot.cloud.common.web.interceptor;
+
+/*
+ **********************************************
+ * DATE PERSON REASON
+ * 2020-12-04 FXY Created
+ **********************************************
+ */
+
+
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.DigestUtils;
+
+import java.util.Collection;
+import java.util.Map;
+
+
+@Slf4j
+public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {
+
+ public FeignBasicAuthRequestInterceptor(){
+ log.info("========================加载自定义拦截器=========================");
+ }
+
+ //服务间调用头
+ private static final String SERVER_CLIENT_TOKEN="server-client-token";
+ //服务间调用秘钥
+ private static final String SERVER_CLIENT_SECRET="server";
+ //网关调用服务头
+ private static final String X_CLIENT_TOKEN="x-client-token";
+
+ @Override
+ public void apply(RequestTemplate requestTemplate) {
+ String url = requestTemplate.path();
+ Map> headers = requestTemplate.headers();
+ if(!headers.containsKey(X_CLIENT_TOKEN)){
+ String method = requestTemplate.method();
+ String originStr = new StringBuilder().append(url).append(method).append(SERVER_CLIENT_TOKEN).append(SERVER_CLIENT_SECRET).toString();
+ // 加入自定义头信息
+ String md5Secret = DigestUtils.md5DigestAsHex(originStr.getBytes());
+ requestTemplate.header(SERVER_CLIENT_TOKEN, md5Secret);
+ }
+ }
+}
\ No newline at end of file
diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/interceptor/UserInterceptor.java b/common/web/src/main/java/com/springboot/cloud/common/web/interceptor/UserInterceptor.java
new file mode 100644
index 0000000..261019f
--- /dev/null
+++ b/common/web/src/main/java/com/springboot/cloud/common/web/interceptor/UserInterceptor.java
@@ -0,0 +1,87 @@
+package com.springboot.cloud.common.web.interceptor;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.springboot.cloud.common.core.util.UserContextHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.lang.Nullable;
+import org.springframework.util.DigestUtils;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * 用户信息拦截器
+ */
+@Slf4j
+public class UserInterceptor implements HandlerInterceptor {
+ /**
+ * 服务间调用token用户信息,格式为json
+ * {
+ * "user_name":"必须有"
+ * "自定义key:"value"
+ * }
+ */
+ //获取相关授权信息请求头
+ private static final String X_CLIENT_TOKEN_USER = "x-client-token-user";
+
+ //网关调用服务请求头
+ private static final String X_CLIENT_TOKEN = "x-client-token";
+
+ //网关调用服务秘钥
+ private static final String X_CLIENT_SECRET = "gateway-web";
+
+ //服务间调用请求头
+ private static final String SERVER_CLIENT_TOKEN = "server-client-token";
+
+ //服务间调用秘钥
+ private static final String SERVER_CLIENT_SECRET = "server";
+
+ //当前用户登录公司
+ private static final String USER_CURRENT_COMPANY = "company";
+
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ //从网关获取并校验,通过校验就可信任x-client-token-user中的信息
+ boolean b = checkToken(request);
+ if (!b) {
+ //重定向到登录前端
+ response.sendRedirect("https://www.baidu.com");
+ return b;
+ }
+
+ //放入上下文数据
+ String userInfoString = StringUtils.defaultIfBlank(request.getHeader(X_CLIENT_TOKEN_USER), "{}");
+ Map context = new ObjectMapper().readValue(userInfoString, Map.class);
+ context.put("company", request.getHeader(USER_CURRENT_COMPANY));
+ UserContextHolder.getInstance().setContext(context);
+ return true;
+ }
+
+ private boolean checkToken(HttpServletRequest request) {
+ String method = request.getMethod();
+ String url = request.getServletPath();
+ Optional serverToken = Optional.ofNullable(request.getHeader(SERVER_CLIENT_TOKEN));
+ Optional clientToken = Optional.ofNullable(request.getHeader(X_CLIENT_TOKEN));
+ if (serverToken.isPresent()) {
+ //如果是服务间相互调用不需要加contextPath,因为feign拦截器中加密是根据servletPath来加密的,此处也是根据servletPath解密的
+ String originStr = new StringBuilder().append(url).append(method).append(SERVER_CLIENT_TOKEN).append(SERVER_CLIENT_SECRET).toString();
+ return DigestUtils.md5DigestAsHex(originStr.getBytes()).equals(serverToken.get());
+ } else if (clientToken.isPresent()) {
+ //如果是网关调用服务,网关服务需要加上contextPath
+ String originStr = new StringBuilder().append(request.getContextPath().concat(url)).append(method).append(X_CLIENT_TOKEN).append(X_CLIENT_SECRET).toString();
+ return DigestUtils.md5DigestAsHex(originStr.getBytes()).equals(clientToken.get());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
+ UserContextHolder.getInstance().clear();
+ }
+}
diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/redis/RedisConfig.java b/common/web/src/main/java/com/springboot/cloud/common/web/redis/RedisConfig.java
new file mode 100644
index 0000000..2d0257a
--- /dev/null
+++ b/common/web/src/main/java/com/springboot/cloud/common/web/redis/RedisConfig.java
@@ -0,0 +1,48 @@
+package com.springboot.cloud.common.web.redis;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.cache.RedisCacheWriter;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+
+import java.time.Duration;
+
+@Configuration
+public class RedisConfig extends CachingConfigurerSupport {
+
+ @Bean
+ public CacheManager cacheManager(RedisConnectionFactory factory) {
+ //对象的序列化
+ RedisSerializationContext.SerializationPair valueSerializationPair
+ = RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer());
+ //全局redis缓存过期时间
+ RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
+ .entryTtl(Duration.ofDays(1))
+// .serializeKeysWith()
+ .serializeValuesWith(valueSerializationPair);
+
+ return new RedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(factory), redisCacheConfiguration);
+ }
+
+ private Jackson2JsonRedisSerializer