文章目录

  • 1.启动配置文件
  • 2..gitignore文件
  • 3.logback.xml日志文件
  • 4.Swagger2Config
  • 5.WebConfigurer
  • 6.Result
  • 7.JeecgBootException
  • 8.JeecgBootExceptionHandler
  • 9.MybatisPlusConfig
  • 10.RedisLock
  • 11.redis
  • 12.RabbitMqConfig
1.启动配置文件

application.yml

spring:profiles:active: local

application-local.yml

server:servlet:context-path: /bfp-o2o#Spring 相关配置
spring:autoconfigure:exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfiguredatasource:dynamic:#设置默认的数据源或者数据源组,默认值即为masterprimary: masterstrict: falsedatasource:master:driver-class-name: com.mysql.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://10.239.183.66:3306/o2o?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false#          url: jdbc:mysql://10.201.1.222:3306/o2o?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=falseusername: rootpassword: cw68_sit@crv
o2o:jd:file:remotePath: /home/ftpuser/jd/remoteFileName: jd-back.csvlocalPath: ./data/jd/localFileName: jd-back.csvmt:file:remotePath: /home/ftpuser/meituan/remoteFileName: mt.csvlocalPath: ./data/meituan/localFileName: mt.csveleme:file:remotePath: /home/ftpuser/eleme/remoteFileName: eleme.csvlocalPath: ./data/eleme/localFileName: eleme.csvshop_ids_url: https://o2o-api.crv.com.cn/open_api/v1/dc-shopsuguo_url: https://wei-test.vipxiaoqu.com/wty-testsftp:name: ftpuserpasswd: ftpP#ssw0rdipAddr: 10.201.1.223port: 22#mybatis-plus配置
mybatis-plus:configuration:map-underscore-to-camel-case: truecall-setters-on-nulls: trueauto-mapping-behavior: fulllog-impl: org.apache.ibatis.logging.stdout.StdOutImplmapper-locations: classpath*:mapper/**/*Mapper.xmlglobal-config:banner: false# 逻辑删除配置db-config:id-type: AUTOlogic-delete-field: delFlaglogic-delete-value: 1logic-not-delete-value: 0table-underline: true

bootstrap.yml

spring:application:name: o2o-servicecloud:nacos:config:file-extension: yaml

启动参数

-Dspring.cloud.nacos.discovery.serverAddr=10.239.165.190:80 -Dspring.cloud.nacos.discovery.namespace=bfp-sit -Dspring.cloud.nacos.config.serverAddr=10.239.165.190:80 -Dspring.cloud.nacos.config.namespace=bfp-sit
2…gitignore文件
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/### VS Code ###
.vscode/
3.logback.xml日志文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false"><include resource="org/springframework/boot/logging/logback/defaults.xml"/><include resource="org/springframework/boot/logging/logback/console-appender.xml"/><!--定义日志文件的存储地址 --><property name="APPDIR" value="o2o-api"/><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><File>log/${APPDIR}.out</File><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern></encoder><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 添加.gz 历史日志会启用压缩 大大缩小日志文件所占空间 --><fileNamePattern>log/daily/${APPDIR}.%d{yyyy-MM-dd}.gz</fileNamePattern><maxHistory>7</maxHistory><!--  保留7天日志 --></rollingPolicy></appender><!--myibatis log configure --><logger name="com.apache.ibatis" level="TRACE"/><logger name="java.sql.Connection" level="DEBUG"/><logger name="java.sql.Statement" level="DEBUG"/><logger name="java.sql.PreparedStatement" level="DEBUG"/><logger name="com.wanjia.o2o" level="INFO"/><!-- 日志输出级别 --><root level="info"><appender-ref ref="CONSOLE"/><appender-ref ref="FILE"/></root></configuration>
4.Swagger2Config
package org.jeecg.config;import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.shiro.vo.DefContants;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.Parameter;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;/*** @Author scott*/
@Slf4j
@Configuration
@EnableSwagger2
@EnableSwaggerBootstrapUI
@ConditionalOnProperty(name = "swagger.enable", havingValue = "true")
public class Swagger2Config implements WebMvcConfigurer {/*** 显示swagger-ui.html文档展示页,还必须注入swagger资源:** @param registry*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}Predicate<RequestHandler> selector1 = RequestHandlerSelectors.basePackage("org.jeecg.modules");Predicate<RequestHandler> selector2 = RequestHandlerSelectors.basePackage("com.eastroc");/*** swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等** @return Docket*/@Beanpublic Docket createRestApi() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).groupName("预约系统").select()//此包路径下的类,才生成接口文档
//                .apis(RequestHandlerSelectors.basePackage("org.jeecg.modules"))//加了ApiOperation注解的类,才生成接口文档.apis(Predicates.or(selector1, selector2)).apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).paths(PathSelectors.any()).build().securitySchemes(Collections.singletonList(securityScheme())).globalOperationParameters(setHeaderToken());}@Beanpublic Docket createVrsRestApi() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).groupName("ARRANGE模块").select()//此包路径下的类,才生成接口文档.apis(RequestHandlerSelectors.basePackage("com.eastroc"))//加了ApiOperation注解的类,才生成接口文档.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).paths(PathSelectors.any()).build().securitySchemes(Collections.singletonList(securityScheme()));
//                .globalOperationParameters(setHeaderToken());}/**** oauth2配置* 需要增加swagger授权回调地址* http://localhost:8888/webjars/springfox-swagger-ui/o2c.html* @return*/@BeanSecurityScheme securityScheme() {return new ApiKey(DefContants.X_ACCESS_TOKEN, DefContants.X_ACCESS_TOKEN, "header");}/*** JWT token** @return*/private List<Parameter> setHeaderToken() {ParameterBuilder tokenPar = new ParameterBuilder();List<Parameter> pars = new ArrayList<>();tokenPar.name(DefContants.X_ACCESS_TOKEN).description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build();pars.add(tokenPar.build());return pars;}/*** api文档的详细信息函数,注意这里的注解引用的是哪个** @return*/private ApiInfo apiInfo() {return new ApiInfoBuilder()// //大标题.title("Jeecg-Boot 后台服务API接口文档")// 版本号.version("1.0")
//              .termsOfServiceUrl("NO terms of service")// 描述.description("后台API接口")// 作者.contact("JEECG团队").license("The Apache License, Version 2.0").licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html").build();}}
/*** @author : qinyingjie* @date : 2021/10/26* @desc : http://localhost:8080/ant/doc.html#/home*/
@Configuration
@EnableOpenApi     //开启 Swagger3 ,可不写
@EnableKnife4j     //开启 knife4j ,可不写
public class Knife4jConfig {@Beanpublic Docket createRestApi() {// Swagger 2 使用的是:DocumentationType.SWAGGER_2// Swagger 3 使用的是:DocumentationType.OAS_30return new Docket(DocumentationType.OAS_30)// 定义是否开启swagger,false为关闭,可以通过变量控制.enable(true)// 将api的元信息设置为包含在json ResourceListing响应中。.apiInfo(new ApiInfoBuilder().title("ANT接口文档")// 描述.description("平台服务管理api").contact(new Contact("秦英杰", "深圳", "327782001@qq.com")).version("1.0.0").build())// 分组名称.groupName("1.0")// 选择哪些接口作为swagger的doc发布.select()// 要扫描的API(Controller)基础包.apis(RequestHandlerSelectors.basePackage("com.xiaofei"))//                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).paths(PathSelectors.any()).build();}
}
5.WebConfigurer
package com.eastroc.login;import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.eastroc.common.enums.RoleEnum;
import com.eastroc.common.service.ISystemFixService;
import com.eastroc.common.utils.LoginUtils;
import com.eastroc.mine.entity.SystemFix;
import com.eastroc.mine.entity.UserWechat;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.exception.RoleException;
import org.jeecg.common.exception.SystemMaintenanceException;
import org.jeecg.common.exception.UserException;
import org.jeecg.common.util.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Objects;@Slf4j
@Component
public class XcxRoleInterceptor extends HandlerInterceptorAdapter {@Autowiredprivate ISystemFixService systemFixService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {List<SystemFix> systemFixes = systemFixService.list();if (CollectionUtils.isNotEmpty(systemFixes)) {SystemFix systemFix = systemFixes.get(0);//系统维护通知long startInterval = DateUtil.between(systemFix.getFixStart(), new Date(), DateUnit.MS, false);long endInterval = DateUtil.between(new Date(), systemFix.getFixEnd(), DateUnit.MS, false);if (startInterval > 0 && endInterval > 0) {String endDate = DateUtils.date2Str(systemFix.getFixEnd(), DateUtils.datetimeFormat.get());throw new SystemMaintenanceException("系统维护中,维护时间至:" + endDate);}}UserWechat user = LoginUtils.getCurrentUser(request);if (Objects.isNull(user)) {throw new UserException("登录信息没有" + request.getRequestURL());}if (Objects.isNull(user.getRoleId())) {throw new UserException("登录角色没有" + request.getRequestURL() + "" + user.toString());}HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();XcxRole role = method.getAnnotation(XcxRole.class);if (Objects.isNull(role)) {return true;}if (role.roles().length > 0) {Integer currentRole = user.getRoleId();for (RoleEnum annotationRole : role.roles()) {if (currentRole.equals(annotationRole.getType())) {return true;}}}throw new RoleException("用户越权访问接口");}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}}
6.Result
package org.jeecg.common.api.vo;import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.jeecg.common.constant.CommonConstant;
import lombok.Data;/***   接口返回数据格式* @author scott* @email jeecgos@163.com* @date  2019年1月19日*/
@Data
@ApiModel(value="接口返回对象", description="接口返回对象")
public class Result<T> implements Serializable {private static final long serialVersionUID = 1L;/*** 成功标志*/@ApiModelProperty(value = "成功标志")private boolean success = true;/*** 返回处理消息*/@ApiModelProperty(value = "返回处理消息")private String message = "操作成功!";/*** 返回代码*/@ApiModelProperty(value = "返回代码")private Integer code = 0;/*** 返回数据对象 data*/@ApiModelProperty(value = "返回数据对象")private T result;/*** 时间戳*/@ApiModelProperty(value = "时间戳")private long timestamp = System.currentTimeMillis();public Result() {}public Result<T> success(String message) {this.message = message;this.code = CommonConstant.SC_OK_200;this.success = true;return this;}public Result<T> good(T t) {this.setResult(t);this.code = CommonConstant.SC_OK_200;this.success = true;return this;}public Result<T> good() {this.code = CommonConstant.SC_OK_200;this.success = true;this.setMessage("成功");return this;}public Result<T> fail(String msg) {this.setCode(CommonConstant.SC_INTERNAL_SERVER_ERROR_500);this.setMessage(msg);this.setSuccess(false);return this;}public static Result<Object> ok() {Result<Object> r = new Result<Object>();r.setSuccess(true);r.setCode(CommonConstant.SC_OK_200);r.setMessage("成功");return r;}public static Result<Object> ok(String msg) {Result<Object> r = new Result<Object>();r.setSuccess(true);r.setCode(CommonConstant.SC_OK_200);r.setMessage(msg);return r;}public static Result<Object> ok(Object data) {Result<Object> r = new Result<Object>();r.setSuccess(true);r.setCode(CommonConstant.SC_OK_200);r.setResult(data);return r;}public static Result<Object> error(String msg) {return error(CommonConstant.SC_INTERNAL_SERVER_ERROR_500, msg);}public static Result<Object> error(int code, String msg) {Result<Object> r = new Result<Object>();r.setCode(code);r.setMessage(msg);r.setSuccess(false);return r;}public Result<T> error500(String message) {this.message = message;this.code = CommonConstant.SC_INTERNAL_SERVER_ERROR_500;this.success = false;return this;}/*** 无权限访问返回结果*/public static Result<Object> noauth(String msg) {return error(CommonConstant.SC_JEECG_NO_AUTHZ, msg);}
}
7.JeecgBootException
package org.jeecg.common.exception;public class JeecgBootException extends RuntimeException {private static final long serialVersionUID = 1L;private Integer code;public JeecgBootException(String message) {super(message);}public JeecgBootException(Integer code, String message) {super(message);this.code = code;}public JeecgBootException(Throwable cause) {super(cause);}public JeecgBootException(String message, Throwable cause) {super(message, cause);}
}
8.JeecgBootExceptionHandler
package org.jeecg.common.exception;import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.jeecg.common.api.vo.Result;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.connection.PoolException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException;import java.util.Arrays;/*** 异常处理器** @Author scott* @Date 2019*/
@Slf4j
@RestControllerAdvice
public class JeecgBootExceptionHandler {@Value("${profileCurrentValue}")private String profileCurrentValue;/*** 处理自定义异常*/@ExceptionHandler(JeecgBootException.class)public Result<?> handleRRException(JeecgBootException e) {log.error(e.getMessage(), e);return Result.error(e.getMessage());}@ExceptionHandler(RoleException.class)public Result<?> handleRoleException(RoleException e) {log.error(e.getMessage(), e);return Result.error("用户角色异常");}@ExceptionHandler(UserException.class)public Result<?> handleUserException(UserException e) {log.error(e.getMessage(), e);return Result.error("用户登录异常");}@ExceptionHandler(SystemMaintenanceException.class)public Result<?> handleSystemMaintenanceException(SystemMaintenanceException e) {log.error(e.getMessage(), e);return Result.error(e.getMessage());}@ExceptionHandler(NoHandlerFoundException.class)public Result<?> handlerNoFoundException(Exception e) {log.error(e.getMessage(), e);return Result.error(404, "路径不存在,请检查路径是否正确");}@ExceptionHandler(DuplicateKeyException.class)public Result<?> handleDuplicateKeyException(DuplicateKeyException e) {log.error(e.getMessage(), e);return Result.error("数据库中已存在该记录");}@ExceptionHandler({UnauthorizedException.class, AuthorizationException.class})public Result<?> handleAuthorizationException(AuthorizationException e) {log.error(e.getMessage(), e);return Result.noauth("没有权限,请联系管理员授权");}@ExceptionHandler({Exception.class})public Result<?> handleException(Exception e) {log.error(e.getMessage(), e);String env = "小程序";if ("dev".equals(profileCurrentValue)) {return Result.error("操作失败," + e.getMessage());
//          env = "开发环境";} else if ("test".equals(profileCurrentValue)) {env += "测试环境";} else if ("prod".equals(profileCurrentValue)) {env += "生产环境";}HttpRequest.post("https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=8315d403-91d3-4bc2-bc72-91bd92a38a51").header(Header.CONTENT_TYPE, "application/json").body("  {\n" +"        \"msgtype\": \"text\",\n" +"        \"text\": {\n" +"            \"content\": \"" + env + "\n" + e.toString() + "\n" + Arrays.toString(e.getStackTrace()).substring(0, 500) + "\"\n" +"        }\n" +"   }").execute();return Result.error("操作失败," + e.getMessage());}/*** 自定义系统交互异常*/@ExceptionHandler(SystemException.class)public Result<?> handleSystemException(SystemException e) {log.error(e.getMessage(), e);String env = "小程序";if ("dev".equals(profileCurrentValue)) {//            return Result.error("操作失败," + e.getMessage());env = "开发环境";} else if ("test".equals(profileCurrentValue)) {env += "测试环境";} else if ("prod".equals(profileCurrentValue)) {env += "生产环境";}env = env + "--系统交互异常";HttpRequest.post("https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=8315d403-91d3-4bc2-bc72-91bd92a38a51").header(Header.CONTENT_TYPE, "application/json").body("  {\n" +"        \"msgtype\": \"text\",\n" +"        \"text\": {\n" +"            \"content\": \"" + env + "\n" + e.toString() + "\n" + e.getMessage() + "\"\n" +"        }\n" +"   }").execute();return Result.error(e.getMessage());}/*** @param e* @return* @Author 政辉*/@ExceptionHandler(HttpRequestMethodNotSupportedException.class)public Result<?> HttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {StringBuffer sb = new StringBuffer();sb.append("不支持");sb.append(e.getMethod());sb.append("请求方法,");sb.append("支持以下");String[] methods = e.getSupportedMethods();if (methods != null) {for (String str : methods) {sb.append(str);sb.append("、");}}log.error(sb.toString(), e);//return Result.error("没有权限,请联系管理员授权");return Result.error(405, sb.toString());}/*** spring默认上传大小100MB 超出大小捕获异常MaxUploadSizeExceededException*/@ExceptionHandler(MaxUploadSizeExceededException.class)public Result<?> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {log.error(e.getMessage(), e);return Result.error("文件大小超出10MB限制, 请压缩或降低文件质量! ");}@ExceptionHandler(DataIntegrityViolationException.class)public Result<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) {log.error(e.getMessage(), e);return Result.error("字段太长,超出数据库字段的长度");}@ExceptionHandler(PoolException.class)public Result<?> handlePoolException(PoolException e) {log.error(e.getMessage(), e);return Result.error("Redis 连接异常!");}}
package com.xiaofei.common.constant;public class CommonConstant {/*** 成功*/public static final Integer SC_OK_200 = 200;/*** 服务器错误*/public static final Integer SC_INTERNAL_SERVER_ERROR_500 = 500;/*** 未认证*/public static final int SC_JEECG_NO_AUTHZ = 401;
}
9.MybatisPlusConfig
package org.jeecg.config;import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.jeecg.config.mybatis.MetaHandler;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.aop.interceptor.PerformanceMonitorInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;/*** 单数据源配置(jeecg.datasource.open = false时生效)** @Author zhoujf*/
@Configuration
@MapperScan(value = {"org.jeecg.modules.**.mapper*", "com.eastroc.**.mapper*"})
public class MybatisPlusConfig {/*** 分页插件*/@Beanpublic PaginationInterceptor paginationInterceptor() {// 设置sql的limit为无限制,默认是500return new PaginationInterceptor().setLimit(-1);}/*** 自动填充功能** @return*/@Beanpublic GlobalConfig globalConfig() {GlobalConfig globalConfig = new GlobalConfig();globalConfig.setMetaObjectHandler(new MetaHandler());return globalConfig;}@Bean@Profile({"dev", "test"}) // 在dev和test环境中开启 SQL执行效率插件【生产环境可以关闭】public PerformanceMonitorInterceptor performanceMonitorInterceptor() {return new PerformanceMonitorInterceptor();}@Beanpublic ISqlInjector sqlInjector() {return new LogicSqlInjector();}
}
package com.xiaofei.common.config;import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;import java.time.LocalDateTime;
import java.util.Date;
import java.util.function.Supplier;public class MetaHandler implements MetaObjectHandler {private static String CREATE_TIME = "createTime";private static String UPDATE_TIME = "updateTime";/*** 插入使用*/@Overridepublic void insertFill(MetaObject metaObject) {fillValue(metaObject, CREATE_TIME, () -> getDateValue(metaObject.getSetterType(CREATE_TIME)));fillValue(metaObject, UPDATE_TIME, () -> getDateValue(metaObject.getSetterType(UPDATE_TIME)));}/*** 更新使用*/@Overridepublic void updateFill(MetaObject metaObject) {fillValue(metaObject, "et." + UPDATE_TIME, () -> getDateValue(metaObject.getSetterType("et." + UPDATE_TIME)));}private void fillValue(MetaObject metaObject, String fieldName, Supplier<Object> valueSupplier) {if (!metaObject.hasGetter(fieldName)) {return;}Object sidObj = metaObject.getValue(fieldName);if (sidObj == null && metaObject.hasSetter(fieldName) && valueSupplier != null) {setFieldValByName(fieldName, valueSupplier.get(), metaObject);}}private Object getDateValue(Class<?> setterType) {if (Date.class.equals(setterType)) {return new Date();} else if (LocalDateTime.class.equals(setterType)) {return LocalDateTime.now();} else if (Long.class.equals(setterType)) {return System.currentTimeMillis();}return null;}
}
10.RedisLock
package org.jeecg.common.aspect.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisLock {/*** 获取方法上的参数值生成key,spEl表达式:例如'#{data}'或者 '#{data.value}'或者 '#{data.value1}&#{data.value2}'*/String key() default "";/*** 自定义后缀,字符串,加在key的后面*/String suffix() default "";/*** key过期时间,毫秒,默认10秒*/String expireTime() default "10000";/*** 是否包含token值,需要请求头里包含token*/boolean includeToken() default false;
}
@RedisLock(key = "#data")
@AutoLog(value = "供应链新增订单到预约系统")
@ApiOperation(value = "供应链新增订单到预约系统", notes = "供应链新增订单到预约系统")
@PostMapping(value = "/expressOrder")
public Map<String, Object> expressOrder(@RequestBody String data) {}
package org.jeecg.modules.system.aspect;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.jeecg.common.aspect.annotation.RedisLock;
import org.jeecg.common.util.redis.JedisClient;
import org.jeecg.common.util.redis.RedisTool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.UUID;@Slf4j
@Aspect
@Configuration
public class RedisLockAspect {@Autowiredprivate JedisClient jedisClient;@Around(value = "@annotation(org.jeecg.common.aspect.annotation.RedisLock)")public Object doAround(ProceedingJoinPoint pjp) throws Throwable {MethodSignature methodSignature = (MethodSignature) pjp.getSignature();Method method = methodSignature.getMethod();RedisLock redisLock = method.getAnnotation(RedisLock.class);Object[] arguments = pjp.getArgs();//解析SpEL表达式String key = String.valueOf(parseSpel(redisLock.key(), method, arguments));//解析UserId表达式String token = parseToken(redisLock.includeToken());Object result;String methodName = pjp.getSignature().getName();//唯一标识String requestId = UUID.randomUUID().toString();String lockKey = "vrs_" + methodName + "_" + token + key;//后缀if (StringUtils.isNotBlank(redisLock.suffix())) {lockKey = lockKey + "_" + redisLock.suffix();}try {//添加分布式锁boolean res = RedisTool.tryGetDistributedLock(jedisClient.getJedis(), lockKey, requestId, Integer.parseInt(redisLock.expireTime()));if (res) {//执行result = pjp.proceed();} else {log.info("重复提交的请求: " + lockKey);throw new Exception("重复提交的请求");}} catch (Exception e) {log.error(e.getMessage(), e);throw e;} finally {//移除分布式锁RedisTool.releaseDistributedLock(jedisClient.getJedis(), lockKey, requestId);log.info("释放分布式锁成功: " + lockKey);}return result;}private String parseToken(boolean includeToken) {if (includeToken) {RequestAttributes ra = RequestContextHolder.getRequestAttributes();ServletRequestAttributes sra = (ServletRequestAttributes) ra;if (sra != null && sra.getRequest() != null) {HttpServletRequest request = sra.getRequest();Object token = request.getHeader("token_manage");return token == null ? "" : token.toString();}}return "";}/*** 解析SpEL表达式* @param key    SpEL表达式* @param method 反射得到的方法* @param args   反射得到的方法参数* @return 解析后SpEL表达式对应的值*/private Object parseSpel(String key, Method method, Object[] args) {if (StringUtils.isNotBlank(key)) {// 创建解析器ExpressionParser parser = new SpelExpressionParser();// 通过Spring的LocalVariableTableParameterNameDiscoverer获取方法参数名列表LocalVariableTableParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);// 构造上下文EvaluationContext context = new StandardEvaluationContext();if (args.length == parameterNames.length) {for (int i = 0, len = args.length; i < len; i++) {// 使用setVariable方法来注册自定义变量context.setVariable(parameterNames[i], args[i]);}}String[] keys = key.split("&");StringBuilder sb = new StringBuilder();if (keys.length > 0) {for (String k : keys) {sb.append(parser.parseExpression(k).getValue(context));}}return sb.toString();}return "";}
}
11.redis
package org.jeecg.common.util.redis;import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;import java.util.Collections;@Component
public class RedisTool {private static final String LOCK_SUCCESS = "OK";private static final String SET_IF_NOT_EXIST = "NX"; //  NX 代表只在键不存在时,才对键进行设置操作private static final String SET_WITH_EXPIRE_TIME = "PX"; // PX 5000 设置键的过期时间为5000毫秒/*** 尝试获取分布式锁* @param jedis Redis客户端* @param lockKey 锁* @param requestId 请求标识* @param expireTime 超期时间* @return 是否获取成功*/public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {/*** 1、把key、value set到redis中,隐含覆盖,默认的ttl是-1(永不过期)** 2、根据第三个参数,把key、value set到redis中*     nx : not exists, 只有key 不存在时才把key value set 到redis*     xx : is exists ,只有 key 存在是,才把key value set 到redis** 3、4 和2 就相同,只是多加了个过期时间*      expx参数有两个值可选 :*           ex : seconds 秒*           px :   milliseconds 毫秒*      使用其他值,抛出 异常 : redis.clients.jedis.exceptions.JedisDataException : ERR syntax error*/try {String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);if (LOCK_SUCCESS.equals(result)) {return true;}}finally {if (jedis != null) {jedis.close();}}return false;}private static final Long RELEASE_SUCCESS = 1L;/*** 释放分布式锁* @param jedis Redis客户端* @param lockKey 锁* @param requestId 请求标识* @return 是否释放成功*/public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {try {String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));if (RELEASE_SUCCESS.equals(result)) {return true;}}finally {if (jedis != null) {jedis.close();}}return false;}}
package org.jeecg.common.util.redis;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;@Data
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
public class JedisConfig {private String host;private String password;private String port;private String timeout;private String maxTotal;private String maxIdle;private String minIdle;
}
package org.jeecg.common.util.redis;import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.TimeUnit;@Slf4j
@Component
public class JedisClient {@Autowiredprivate JedisConfig jedisConfig;//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;private static int MAX_WAIT = 15 * 1000;//超时时间private static int TIMEOUT = 10 * 1000;private JedisPool jedisPool = null;public JedisPool getJedisPool() {return jedisPool;}/*** Jedis实例获取返回码** @author jqlin*/public static class JedisStatus {/*** Jedis实例获取失败*/public static final long FAIL_LONG = -5L;/*** Jedis实例获取失败*/public static final int FAIL_INT = -5;/*** Jedis实例获取失败*/public static final String FAIL_STRING = "-5";}@PostConstructprivate void initialPool() {//Redis服务器IPString HOST = jedisConfig.getHost();//Redis的端口号int PORT = NumberUtils.toInt(jedisConfig.getPort(), 6379);//访问密码String AUTH = jedisConfig.getPassword();try {JedisPoolConfig config = new JedisPoolConfig();//最大连接数,如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。config.setMaxTotal(NumberUtils.toInt(jedisConfig.getMaxTotal(), 400));//最大空闲数,控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。config.setMaxIdle(NumberUtils.toInt(jedisConfig.getMaxIdle(), 50));//最小空闲数config.setMinIdle(NumberUtils.toInt(jedisConfig.getMinIdle(), 10));//是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个config.setTestOnBorrow(false);//在return给pool时,是否提前进行validate操作config.setTestOnReturn(false);//在空闲时检查有效性,默认falseconfig.setTestWhileIdle(true);//表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;//这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义config.setMinEvictableIdleTimeMillis(30000);//表示idle object evitor两次扫描之间要sleep的毫秒数config.setTimeBetweenEvictionRunsMillis(60000);//表示idle object evitor每次扫描的最多的对象数config.setNumTestsPerEvictionRun(1000);//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;config.setMaxWaitMillis(MAX_WAIT);if (StringUtils.isNotBlank(AUTH)) {jedisPool = new JedisPool(config, HOST, PORT, TIMEOUT, AUTH);} else {jedisPool = new JedisPool(config, HOST, PORT, TIMEOUT);}} catch (Exception e) {if (jedisPool != null) {jedisPool.close();}log.error("初始化Redis连接池失败", e);}}/*** 在多线程环境同步初始化*/private synchronized void poolInit() {if (jedisPool == null) {initialPool();}}/*** 同步获取Jedis实例** @return Jedis*/public Jedis getJedis() {if (jedisPool == null) {poolInit();}Jedis jedis = null;try {if (jedisPool != null) {jedis = jedisPool.getResource();}} catch (Exception e) {log.error("同步获取Jedis实例失败" + e.getMessage(), e);jedis.close();}return jedis;}/*** 设置值** @param key* @param value* @return -5:Jedis实例获取失败<br/>OK:操作成功<br/>null:操作失败* @author jqlin*/public String set(String key, String value) {try (Jedis jedis = getJedis();) {if (jedis == null) {return JedisStatus.FAIL_STRING;}return jedis.set(key, value);} catch (Exception e) {log.error("[redis error] -> 设置值失败");throw new RuntimeException(e);}}/*** 设置值** @param key* @param value* @param expire 过期时间,单位:秒* @return -5:Jedis实例获取失败<br/>OK:操作成功<br/>null:操作失败* @author jqlin*/public String set(String key, String value, int expire, TimeUnit timeUnit) {try (Jedis jedis = getJedis()) {if (jedis == null) {return JedisStatus.FAIL_STRING;}if (TimeUnit.MILLISECONDS.equals(timeUnit)) {expire = expire / 1000;} else if (!TimeUnit.SECONDS.equals(timeUnit)) {throw new RuntimeException("TimeUnit时间单位设置错误:请设置milliseconds或seconds");}return jedis.setex(key, expire, value);} catch (Exception e) {log.error("[redis error] -> 设置值失败");throw new RuntimeException(e);}}/*** 获取值** @param key* @return* @author jqlin*/public String get(String key) {try (Jedis jedis = getJedis()) {if (jedis == null) {return JedisStatus.FAIL_STRING;}return jedis.get(key);} catch (Exception e) {log.error("[redis error] -> 设置值失败");throw new RuntimeException(e);}}/*** 设置key的过期时间** @param key* @param -5:Jedis实例获取失败,1:成功,0:失败* @return* @author jqlin*/public long expire(String key, int seconds) {try (Jedis jedis = getJedis()) {if (jedis == null) {return JedisStatus.FAIL_LONG;}return jedis.expire(key, seconds);} catch (Exception e) {log.error(String.format("设置key=%s的过期时间失败:" + e.getMessage(), key));throw new RuntimeException(e);}}/*** 判断key是否存在** @param key* @return* @author jqlin*/public boolean exists(String key) {try (Jedis jedis = getJedis();) {if (jedis == null) {log.warn("Jedis实例获取为空");return false;}return jedis.exists(key);} catch (Exception e) {log.error(String.format("判断key=%s是否存在失败:" + e.getMessage(), key));throw new RuntimeException(e);}}/*** 删除key** @param keys* @return -5:Jedis实例获取失败,1:成功,0:失败* @author jqlin*/public long del(String... keys) {try (Jedis jedis = getJedis();) {if (jedis == null) {return JedisStatus.FAIL_LONG;}return jedis.del(keys);} catch (Exception e) {log.error(String.format("删除key=%s失败:" + e.getMessage(), keys));throw new RuntimeException(e);}}/*** set if not exists,若key已存在,则setnx不做任何操作** @param key* @param value key已存在,1:key赋值成功* @return* @author jqlin*/public long setnx(String key, String value) {try (Jedis jedis = getJedis();) {if (jedis == null) {return JedisStatus.FAIL_LONG;}return jedis.setnx(key, value);} catch (Exception e) {log.error("设置值失败:" + e.getMessage());throw new RuntimeException(e);}}/*** set if not exists,若key已存在,则setnx不做任何操作** @param key* @param value  key已存在,1:key赋值成功* @param expire 过期时间,单位:秒* @return* @author jqlin*/public long setnx(String key, String value, int expire) {try (Jedis jedis = getJedis()) {if (jedis == null) {return JedisStatus.FAIL_LONG;}Long result = jedis.setnx(key, value);expire(key, expire);return result;} catch (Exception e) {log.error("设置值失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 在列表key的头部插入元素** @param key* @param values -5:Jedis实例获取失败,>0:返回操作成功的条数,0:失败* @return* @author jqlin*/public long lpush(String key, String... values) {try (Jedis jedis = getJedis();) {if (jedis == null) {return JedisStatus.FAIL_LONG;}return jedis.lpush(key, values);} catch (Exception e) {log.error("在列表key的头部插入元素失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 在列表key的尾部插入元素** @param key* @param values -5:Jedis实例获取失败,>0:返回操作成功的条数,0:失败* @return* @author jqlin*/public long rpush(String key, String... values) {try (Jedis jedis = getJedis()) {if (jedis == null) {return JedisStatus.FAIL_LONG;}return jedis.rpush(key, values);} catch (Exception e) {log.error("在列表key的尾部插入元素失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 返回存储在key列表的特定元素** @param key* @param start 开始索引,索引从0开始,0表示第一个元素,1表示第二个元素* @param end   结束索引,-1表示最后一个元素,-2表示倒数第二个元素* @return redis client获取失败返回null* @author jqlin*/public List<String> lrange(String key, long start, long end) {try (Jedis jedis = getJedis()) {if (jedis == null) {return null;}return jedis.lrange(key, start, end);} catch (Exception e) {log.error("查询列表元素失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 获取List缓存对象** @param key* @param start* @param end* @return List<T> 返回类型* @author jqlin*/public <T> List<T> range(String key, long start, long end, Class<T> clazz) {List<String> dataList = lrange(key, start, end);if (CollectionUtils.isEmpty(dataList)) {return new ArrayList<>();}return JSON.parseArray(JSON.toJSONString(dataList), clazz);}/*** 获取列表长度** @param key -5:Jedis实例获取失败* @return* @author jqlin*/public long llen(String key) {try (Jedis jedis = getJedis()) {if (jedis == null) {return JedisStatus.FAIL_LONG;}return jedis.llen(key);} catch (Exception e) {log.error("获取列表长度失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 移除等于value的元素<br/><br/>* 当count>0时,从表头开始查找,移除count个;<br/>* 当count=0时,从表头开始查找,移除所有等于value的;<br/>* 当count<0时,从表尾开始查找,移除count个** @param key* @param count* @param value* @return -5:Jedis实例获取失败* @author jqlin*/public long lrem(String key, long count, String value) {try (Jedis jedis = getJedis()) {if (jedis == null) {return JedisStatus.FAIL_LONG;}return jedis.lrem(key, count, value);} catch (Exception e) {log.error("获取列表长度失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 对列表进行修剪** @param key* @param start* @param end* @return -5:Jedis实例获取失败,OK:命令执行成功* @author jqlin*/public String ltrim(String key, long start, long end) {try (Jedis jedis = getJedis()) {if (jedis == null) {return JedisStatus.FAIL_STRING;}return jedis.ltrim(key, start, end);} catch (Exception e) {log.error("获取列表长度失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 设置对象** @param key* @param obj* @return* @author jqlin*/public <T> String setObject(String key, T obj) {try (Jedis jedis = getJedis()) {if (jedis == null) {return JedisStatus.FAIL_STRING;}byte[] data = JSON.toJSONBytes(obj);return jedis.set(key.getBytes(), data);} catch (Exception e) {log.error("设置对象失败:" + e.getMessage(), e);throw new RuntimeException(e);}}/*** 获取对象** @param key* @return* @author jqlin*/public <T> T getObject(String key) {try (Jedis jedis = getJedis()) {if (jedis == null) {return null;}T result = null;byte[] data = jedis.get(key.getBytes());if (data != null && data.length > 0) {result = (T) JSON.parse(data);}return result;} catch (Exception e) {log.error("获取对象失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 缓存Map赋值** @param key* @param field* @param value* @return -5:Jedis实例获取失败* @author jqlin*/public long hset(String key, String field, String value) {try (Jedis jedis = getJedis();) {if (jedis == null) {return JedisStatus.FAIL_LONG;}return jedis.hset(key, field, value);} catch (Exception e) {log.error("缓存Map赋值失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 获取缓存的Map值** @param key* @return*/public String hget(String key, String field) {try (Jedis jedis = getJedis();) {if (jedis == null) {return null;}return jedis.hget(key, field);} catch (Exception e) {log.error("获取缓存的Map值失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 缓存Map** @param key* @param map* @return*/public String hmset(String key, Map<String, String> map) {try (Jedis jedis = getJedis();) {if (jedis == null) {return JedisStatus.FAIL_STRING;}return jedis.hmset(key, map);} catch (Exception e) {log.error("缓存Map赋值失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 获取map所有的字段和值** @param key* @return* @author jqlin*/public Map<String, String> hgetAll(String key) {try (Jedis jedis = getJedis()) {if (jedis == null) {log.warn("Jedis实例获取为空");return new HashMap<>();}return jedis.hgetAll(key);} catch (Exception e) {log.error("获取map所有的字段和值失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 查看哈希表 key 中,指定的field字段是否存在。** @param key* @param field* @return* @author jqlin*/public Boolean hexists(String key, String field) {try (Jedis jedis = getJedis()) {if (jedis == null) {log.warn("Jedis实例获取为空");return null;}return jedis.hexists(key, field);} catch (Exception e) {log.error("查看哈希表field字段是否存在失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 获取所有哈希表中的字段** @param key* @return* @author jqlin*/public Set<String> hkeys(String key) {try (Jedis jedis = getJedis();) {if (jedis == null) {log.warn("Jedis实例获取为空");return new HashSet<>();}return jedis.hkeys(key);} catch (Exception e) {log.error("获取所有哈希表中的字段失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 获取所有哈希表中的值** @param key* @return* @author jqlin*/public List<String> hvals(String key) {try (Jedis jedis = getJedis();) {if (jedis == null) {log.warn("Jedis实例获取为空");return new ArrayList<>();}return jedis.hvals(key);} catch (Exception e) {log.error("获取所有哈希表中的值失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 从哈希表 key 中删除指定的field** @param key* @param* @return* @author jqlin*/public long hdel(String key, String... fields) {try (Jedis jedis = getJedis();) {if (jedis == null) {log.warn("Jedis实例获取为空");return JedisStatus.FAIL_LONG;}return jedis.hdel(key, fields);} catch (Exception e) {log.error("map删除指定的field失败:" + e.getMessage());throw new RuntimeException(e);}}/*** 获取正则匹配的key (慎用)** @param pattern* @return*/public Set<String> keys(String pattern) {try (Jedis jedis = getJedis()) {if (jedis == null) {log.warn("Jedis实例获取为空");return new HashSet<>();}return jedis.keys(pattern);} catch (Exception e) {log.error("操作keys失败:" + e.getMessage(), e);throw new RuntimeException(e);}}/*** Redis Incrby 命令将 key 中储存的数字加上指定的增量值;* 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令;* 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。* 本操作的值限制在 64 位(bit)有符号数字表示之内。** @return*/public Long incrBy(String key, long integer) {try (Jedis jedis = getJedis()) {if (jedis == null) {log.warn("Jedis实例获取为空");return 0L;}return jedis.incrBy(key, integer);} catch (Exception e) {log.error("操作 Incrby 失败:" + e.getMessage(), e);throw new RuntimeException(e);}}/*** Redis Incr 命令将 key 中储存的数字值增一。* 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。* 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。* 本操作的值限制在 64 位(bit)有符号数字表示之内*/public Long incr(String key) {try (Jedis jedis = getJedis()) {if (jedis == null) {log.warn("Jedis实例获取为空");return 0L;}return jedis.incr(key);} catch (Exception e) {log.error("操作 Incr 失败:" + e.getMessage(), e);throw new RuntimeException(e);}}
}
12.RabbitMqConfig
package org.jeecg.config;import com.eastroc.common.consts.ArrangeConstant;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@RequiredArgsConstructor
public class RabbitMqConfig {private final SimpleRabbitListenerContainerFactoryConfigurer factoryConfigurer;private final CachingConnectionFactory connectionFactory;@Bean(name = "syncshipmentOrderReportServiceQueue")public Queue syncshipmentOrderReportServiceQueue() {return QueueBuilder.durable(ArrangeConstant.Q_SYNC_SHIPMENT_ORDER_TO_REPORT_ONE).build();}@Beanpublic Binding syncShipmentOrderReportServiceBinding(Queue syncshipmentOrderReportServiceQueue, DirectExchange shipmentOrderReportExchange) {return BindingBuilder.bind(syncshipmentOrderReportServiceQueue).to(shipmentOrderReportExchange).with(ArrangeConstant.K_SHIPMENT_ORDER_REPORT_ONE);}@Bean(name = "shipmentOrderReportContainer")public SimpleRabbitListenerContainerFactory shipmentOrderReportContainer() {SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();factoryConfigurer.configure(factory, connectionFactory);factory.setAcknowledgeMode(AcknowledgeMode.NONE);factory.setPrefetchCount(10);return factory;}@Beanpublic DirectExchange shipmentOrderReportExchange() {return (DirectExchange) ExchangeBuilder.directExchange(ArrangeConstant.E_EXCHANGE).durable(true).build();}}
package com.eastroc.common.consumer;import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.eastroc.common.consts.ArrangeConstant;
import com.eastroc.order.entity.*;
import com.eastroc.order.entity.StoreBase;
import com.eastroc.common.mapper.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;@Slf4j
@Component
@RabbitListener(queues = ArrangeConstant.Q_SYNC_SHIPMENT_ORDER_TO_REPORT_ONE, containerFactory = "shipmentOrderReportContainer")
public class ShipmentOrderReportConsumer {@Resourceprivate StoreBaseMapper storeBaseMapper;@Resourceprivate ShipmentOrderMapper shipmentOrderMapper;@Resourceprivate ShipmentOrderDetailMapper shipmentOrderDetailMapper;@Resourceprivate ShipmentOrderReportMapper shipmentOrderReportMapper;@Resourceprivate ShipmentOrderRelateDriverMapper shipmentOrderRelateDriverMapper;@Resourceprivate AccessControlSystemCarInfoMapper accessControlSystemCarInfoMapper;@Resourceprivate ShipmentOrderDetailGoodsInfoMapper shipmentOrderDetailGoodsInfoMapper;@RabbitHandlerpublic void syncReport(String shipmentOrderId) {log.info("syncReport shipmentOrderId={}", shipmentOrderId);ShipmentOrder shipmentOrder = shipmentOrderMapper.selectOne(Wrappers.<ShipmentOrder>lambdaQuery().eq(ShipmentOrder::getId, shipmentOrderId));List<ShipmentOrderDetail> shipmentOrderDetails = shipmentOrderDetailMapper.selectList(Wrappers.<ShipmentOrderDetail>lambdaQuery().eq(ShipmentOrderDetail::getShipmentOrderId, shipmentOrderId));if (CollectionUtils.isNotEmpty(shipmentOrderDetails)) {shipmentOrderDetails.forEach(item -> {String shipmentDetailId = item.getId();ShipmentOrderRelateDriver shipmentOrderRelateDriver = shipmentOrderRelateDriverMapper.selectOne(Wrappers.<ShipmentOrderRelateDriver>lambdaQuery().eq(ShipmentOrderRelateDriver::getShipmentOrderId, shipmentOrderId));List<ShipmentOrderDetailGoodsInfo> shipmentOrderDetailGoodsInfos = shipmentOrderDetailGoodsInfoMapper.selectList(Wrappers.<ShipmentOrderDetailGoodsInfo>lambdaQuery().eq(ShipmentOrderDetailGoodsInfo::getShipmentOrderDetailId, shipmentDetailId));if (CollectionUtils.isNotEmpty(shipmentOrderDetailGoodsInfos)) {shipmentOrderDetailGoodsInfos.forEach(goodsInfo -> {ShipmentOrderReport shipmentOrderReport = shipmentOrderReportMapper.selectOne(Wrappers.<ShipmentOrderReport>lambdaQuery().eq(ShipmentOrderReport::getTrainNumber, shipmentOrder.getTrainNumber()).eq(ShipmentOrderReport::getOrderNumber, item.getOrderNumber()).eq(ShipmentOrderReport::getGoodsType, goodsInfo.getGoodsType()).eq(ShipmentOrderReport::getProductCode, goodsInfo.getProductCode()));if (shipmentOrderReport == null) {shipmentOrderReport = new ShipmentOrderReport();this.buildShipmentOrderReport(shipmentOrder, item, shipmentOrderRelateDriver, goodsInfo, shipmentOrderReport);shipmentOrderReportMapper.insert(shipmentOrderReport);} else {this.buildShipmentOrderReport(shipmentOrder, item, shipmentOrderRelateDriver, goodsInfo, shipmentOrderReport);shipmentOrderReportMapper.updateById(shipmentOrderReport);}});}if (Objects.isNull(shipmentOrderRelateDriver)) {shipmentOrderReportMapper.update(new ShipmentOrderReport(), Wrappers.<ShipmentOrderReport>lambdaUpdate().set(ShipmentOrderReport::getPeriodDay, null).set(ShipmentOrderReport::getDriverName, null).set(ShipmentOrderReport::getDriverPhone, null).set(ShipmentOrderReport::getCarNumber, null).eq(ShipmentOrderReport::getTrainNumber, shipmentOrder.getTrainNumber()));}});}}/*** 构建报表信息** @param shipmentOrder* @param item* @param shipmentOrderRelateDriver* @param goodsInfo* @param shipmentOrderReport*/private void buildShipmentOrderReport(ShipmentOrder shipmentOrder, ShipmentOrderDetail item, ShipmentOrderRelateDriver shipmentOrderRelateDriver, ShipmentOrderDetailGoodsInfo goodsInfo, ShipmentOrderReport shipmentOrderReport) {//构建基础信息this.buildBaseInfo(shipmentOrder, shipmentOrderReport);//构建详细信息this.buildDetailInfo(item, shipmentOrderReport);//构建约车信息this.buildDriverInfo(shipmentOrderRelateDriver, shipmentOrderReport);//构建产品信息this.buildGoodsInfo(goodsInfo, shipmentOrderReport);}/*** 构建产品信息** @param goodsInfo* @param shipmentOrderReport*/private void buildGoodsInfo(ShipmentOrderDetailGoodsInfo goodsInfo, ShipmentOrderReport shipmentOrderReport) {shipmentOrderReport.setGoodsType(goodsInfo.getGoodsType());shipmentOrderReport.setProductCode(goodsInfo.getProductCode());shipmentOrderReport.setProductName(goodsInfo.getProductName());shipmentOrderReport.setProductType(goodsInfo.getProductType());shipmentOrderReport.setProductWeight(goodsInfo.getProductWeight());shipmentOrderReport.setProductSize(goodsInfo.getProductSize());shipmentOrderReport.setProductNumber(goodsInfo.getProductNumber());shipmentOrderReport.setProductUnit(goodsInfo.getProductUnit());shipmentOrderReport.setDelFlag(goodsInfo.getDelFlag());shipmentOrderReport.setCreateTime(goodsInfo.getCreateTime());shipmentOrderReport.setUpdateTime(goodsInfo.getUpdateTime());shipmentOrderReport.setCreateBy(goodsInfo.getCreateBy());shipmentOrderReport.setUpdateBy(goodsInfo.getUpdateBy());}/*** 构建预约信息** @param shipmentOrderRelateDriver* @param shipmentOrderReport*/private void buildDriverInfo(ShipmentOrderRelateDriver shipmentOrderRelateDriver, ShipmentOrderReport shipmentOrderReport) {if (Objects.nonNull(shipmentOrderRelateDriver)) {shipmentOrderReport.setDriverPhone(shipmentOrderRelateDriver.getDriverPhone());shipmentOrderReport.setDriverName(shipmentOrderRelateDriver.getDriverName());shipmentOrderReport.setPeriodDay(shipmentOrderRelateDriver.getPeriodDay());shipmentOrderReport.setCarNumber(shipmentOrderRelateDriver.getCarNumber());}}/*** 构建订单详情** @param item* @param shipmentOrderReport*/private void buildDetailInfo(ShipmentOrderDetail item, ShipmentOrderReport shipmentOrderReport) {shipmentOrderReport.setAddress(item.getAddress());shipmentOrderReport.setCardBoard(item.getCardBoard());shipmentOrderReport.setOrderNumber(item.getOrderNumber());shipmentOrderReport.setDetailId(item.getId());shipmentOrderReport.setConsigneeName(item.getConsigneeName());shipmentOrderReport.setConsigneePhone(item.getConsigneePhone());shipmentOrderReport.setRealReceiveNumber(item.getRealReceiveNumber());shipmentOrderReport.setDealerNumber(item.getDealerNumber());shipmentOrderReport.setDealerName(item.getDealerName());}/*** 构建车次基础信息** @param shipmentOrder* @param shipmentOrderReport*/private void buildBaseInfo(ShipmentOrder shipmentOrder, ShipmentOrderReport shipmentOrderReport) {shipmentOrderReport.setTrainNumber(shipmentOrder.getTrainNumber());shipmentOrderReport.setOrderStatus(shipmentOrder.getOrderStatus());shipmentOrderReport.setOutTime(shipmentOrder.getOutTime());shipmentOrderReport.setCompany(shipmentOrder.getCompany());shipmentOrderReport.setOutType(shipmentOrder.getOutType());shipmentOrderReport.setDeliveryMode(shipmentOrder.getDeliveryMode());shipmentOrderReport.setDispatchDate(shipmentOrder.getCreateTime());String storeBaseId = shipmentOrder.getStoreBaseId();shipmentOrderReport.setStoreBaseId(storeBaseId);shipmentOrderReport.setStoreBaseName(shipmentOrder.getStoreBaseName());if (StringUtils.isNotBlank(storeBaseId)) {StoreBase storeBase = storeBaseMapper.selectById(storeBaseId);shipmentOrderReport.setStoreBaseCode(storeBase.getBaseCode());}shipmentOrderReport.setModes(shipmentOrder.getModes());AccessControlSystemCarInfo accessControlSystemCarInfo = accessControlSystemCarInfoMapper.selectOne(Wrappers.<AccessControlSystemCarInfo>lambdaQuery().eq(AccessControlSystemCarInfo::getTrainNumber, shipmentOrder.getTrainNumber()).orderByDesc(AccessControlSystemCarInfo::getCreateTime).last("limit 1"));if (accessControlSystemCarInfo != null) {shipmentOrderReport.setInTime(accessControlSystemCarInfo.getInTime());shipmentOrderReport.setSecondWeightTime(accessControlSystemCarInfo.getSecondWeightTime());}}
}
package com.eastroc.common.utils;import com.eastroc.common.consts.ArrangeConstant;
import org.jeecg.common.util.ExecutorServiceFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;import java.util.concurrent.CompletableFuture;@Component
public class TransactionSynchronizationUtil {@Autowiredprivate RabbitTemplate rabbitTemplate;/*** mq同步到历史订单报表** @param shipmentOrderId*/public void syncReportTransaction(String shipmentOrderId) {try {TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {@Overridepublic void afterCommit() {CompletableFuture.runAsync(() -> {rabbitTemplate.convertAndSend(ArrangeConstant.E_EXCHANGE, ArrangeConstant.K_SHIPMENT_ORDER_REPORT_ONE, shipmentOrderId);}, ExecutorServiceFactory.getInstance());}});} catch (Exception e) {e.printStackTrace();}}/*** mq同步到历史订单报表** @param shipmentOrderId*/public void syncReport(String shipmentOrderId) {CompletableFuture.runAsync(() -> {rabbitTemplate.convertAndSend(ArrangeConstant.E_EXCHANGE, ArrangeConstant.K_SHIPMENT_ORDER_REPORT_ONE, shipmentOrderId);}, ExecutorServiceFactory.getInstance());}
}

SpringBoot新项目配置相关推荐

  1. Pycharm新建项目配置虚拟环境

    Pycharm新建项目配置虚拟环境 1.概述 使用python开发项目通常都会创建一个虚拟环境,将项目依赖包安装到虚拟环境中,避免一台电脑上开发多个项目时依赖包版本号不兼容造成冲突. 2.新项目配置虚 ...

  2. 【IDEA工具设置】IDEA引入新项目以及项目配置

    一.IDEA打开新项目 File-->open-->项目文件 二.配置项目依赖 (1)在右上方点击"项目结构" (2)点击后在新界面中配置好需要的项目依赖 三.指定源文 ...

  3. springboot项目配置视图解析器无效的问题

    springboot项目配置视图解析器无效的问题 今天springboot尝试配置视图解析器的时候,如图: 一切正常,视图解析器却始终无效.后面发现问题. 在控制器的注解要使用:@Controller ...

  4. SpringBoot项目配置明文密码泄露问题的处理方式

    SpringBoot项目配置明文密码泄露问题的处理方式: 1.引入jar包 <dependency>     <groupId>com.github.ulisesbocchio ...

  5. IDEA SpringBoot项目配置热更新,无需每次手动重启服务器

    IDEA SpringBoot项目配置热更新的步骤 在pom.xml中添加依赖: <dependency><groupId>org.springframework.boot&l ...

  6. IDEA每次打开新项目Maven配置都会重置

    IDEA每次打开新项目Maven配置都会重置 你有咩有遇到过每次导入项目的时候, 就会有些设置会莫名其妙的重置, 这是因为没有配置打开新项目加载的配置. 首先打开IDEA,然后File,选择New P ...

  7. PyCharm创建新项目:Python解释器配置

    在PyCharm中打开File->New Project创建新项目,首先在Location下选择项目路径,然后打开Project Interpreter配置Python解释器. 如下图,PyCh ...

  8. IDEA配置maven,以及打开新项目默认maven配置

    1.确定你的电脑已成功安装maven,并且配置好的环境变量. 进入cmd窗口,输入mvn -v,检查. mvn -v 2.确定mvn的安装路径. 修改maven中conf文件夹下,setting.xm ...

  9. IDEA中打开新项目maven配置变成默认——解决方案

    修改新项目的Maven配置 前言 解决方法 前言 想必大家都为IDEA中打开新项目时重新配置Maven所苦恼过吧.每次都配置,整个人都不好了,其实只要为新项目设置默认的Maven配置就可以完美解决问题 ...

最新文章

  1. 文巾解题 1035. 不相交的线
  2. php中求数据库两个数的和,php – Doctrine2和Zend框架中的多个数据库连接
  3. Ubuntu下添加定时任务执行php文件
  4. 内网网段划分ciso交换机配置
  5. 跨性别,你所不知道的事
  6. 线性分组码c语言实验报告,C语言线性分组码(附注释).doc
  7. 陌屿授权系统V2.0全解
  8. Spring Boot 配置随机数技巧
  9. 《图解数据结构》.pdf
  10. #金项奖获奖项目专题# | 京东闪付---快人一步
  11. iOS更新系统服务器出错,iPhone 更新失败怎么办?更新 iOS 常见的错误代码及解决方法...
  12. 如何解决安装或者卸载时 临时文件夹已满或不能访问
  13. fail can only be invoked by user TAP gesture.
  14. 用于RF收发器的简单基带处理器详细教程
  15. 力扣(39.40)补9.20
  16. 2021年软考考试科目怎么安排?
  17. 这个650万科学大奖来了!今年颁给谁?
  18. python用户输入字符串串从小到大排序_python字符串从小到大排序
  19. GOG Galaxy连接Ubisoft Connect或者UPlay失败解决方法
  20. Python 是前浪,Julia 是后浪?

热门文章

  1. 测量RT-Thread线程调度的时间的方法
  2. 【SQL】遍历字符串之Substr
  3. python系列——多线程之Semaphore信号量及
  4. Spring实战笔记——(1)Spring之旅(上)
  5. 基于STM32与红外感应开关的自动门设计与实现(结构+设计)
  6. mbedtls学习2.mbedtls从0使用指南
  7. java中getchars是什么意思_java中的getChars()方法
  8. IOS app 上线流程
  9. 一般情况下UniApp打包上线APP流程
  10. 医学主题词表(Medical Subject Headings, MeSH)