commit
b65c4df52a
1780 changed files with 159921 additions and 0 deletions
@ -0,0 +1,58 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<artifactId>cms-api</artifactId> |
|||
<groupId>com.qs</groupId> |
|||
<version>1.0-SNAPSHOT</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<artifactId>cms-admin-svc</artifactId> |
|||
|
|||
<properties> |
|||
<maven.compiler.source>8</maven.compiler.source> |
|||
<maven.compiler.target>8</maven.compiler.target> |
|||
</properties> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>com.qs</groupId> |
|||
<artifactId>cms-framework</artifactId> |
|||
<version>1.0-SNAPSHOT</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.qs</groupId> |
|||
<artifactId>cms-actuator</artifactId> |
|||
<version>1.0-SNAPSHOT</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.qs</groupId> |
|||
<artifactId>cms-system</artifactId> |
|||
<version>1.0-SNAPSHOT</version> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
|
|||
<build> |
|||
<finalName>serve</finalName> |
|||
<plugins> |
|||
<plugin> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-maven-plugin</artifactId> |
|||
<configuration> |
|||
<mainClass>com.qs.serve.Application</mainClass> |
|||
</configuration> |
|||
<executions> |
|||
<execution> |
|||
<goals> |
|||
<goal>repackage</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
|
|||
</project> |
@ -0,0 +1,67 @@ |
|||
package com.qs.serve; |
|||
|
|||
import com.qs.serve.common.config.DevEnvironmentConfig; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.SpringApplication; |
|||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|||
import org.springframework.boot.builder.SpringApplicationBuilder; |
|||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
|||
import org.springframework.cache.annotation.EnableCaching; |
|||
import org.springframework.cloud.openfeign.EnableFeignClients; |
|||
import org.springframework.scheduling.annotation.EnableAsync; |
|||
import org.springframework.scheduling.annotation.EnableScheduling; |
|||
import org.springframework.stereotype.Indexed; |
|||
import org.springframework.transaction.annotation.EnableTransactionManagement; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
import javax.servlet.ServletContext; |
|||
import javax.servlet.ServletException; |
|||
import java.util.TimeZone; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/2/24 |
|||
*/ |
|||
@Indexed |
|||
@EnableAsync |
|||
@EnableScheduling |
|||
@EnableTransactionManagement |
|||
@EnableCaching |
|||
@EnableFeignClients |
|||
@SpringBootApplication |
|||
public class Application extends SpringBootServletInitializer { |
|||
|
|||
@Value("${project.dev}") |
|||
String dev; |
|||
|
|||
public static void main(String[] args) { |
|||
long start = System.currentTimeMillis(); |
|||
SpringApplication.run(Application.class,args); |
|||
long end = System.currentTimeMillis(); |
|||
double diff = (end-start)/1000.0; |
|||
System.out.println("启动时间:"+diff |
|||
+"\n ____ _ _ __ _ _ \n" + |
|||
" / ___| | |_ __ _ _ __ | |_ _ _ _ __ ___ _ _ ___ ___ ___ ___ ___ / _| _ _ | || |\n" + |
|||
" \\___ \\ | __|/ _` || '__|| __| | | | || '_ \\ / __|| | | | / __|/ __|/ _ \\/ __|/ __|| |_ | | | || || |\n" + |
|||
" ___) || |_| (_| || | | |_ | |_| || |_) | \\__ \\| |_| || (__| (__| __/\\__ \\\\__ \\| _|| |_| || ||_|\n" + |
|||
" |____/ \\__|\\__,_||_| \\__| \\__,_|| .__/ |___/ \\__,_| \\___|\\___|\\___||___/|___/|_| \\__,_||_|(_)\n" + |
|||
" |_| \n"); |
|||
} |
|||
|
|||
@Override |
|||
public void onStartup(ServletContext servletContext) throws ServletException { |
|||
super.onStartup(servletContext); |
|||
} |
|||
|
|||
@Override |
|||
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { |
|||
return builder.sources(Application.class); |
|||
} |
|||
|
|||
@PostConstruct |
|||
void started() { |
|||
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai")); |
|||
DevEnvironmentConfig.openDevEnv(dev.equals("true")); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,408 @@ |
|||
package com.qs.serve.controller; |
|||
|
|||
import cn.hutool.crypto.SecureUtil; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.qs.serve.common.config.properties.ProjectProperties; |
|||
import com.qs.serve.common.framework.redis.RedisService; |
|||
import com.qs.serve.common.framework.security.model.LoginUserType; |
|||
import com.qs.serve.common.model.annotation.LimitSubmit; |
|||
import com.qs.serve.common.model.annotation.SysLog; |
|||
import com.qs.serve.common.model.consts.GySysConst; |
|||
import com.qs.serve.common.model.consts.RedisCacheKeys; |
|||
import com.qs.serve.common.model.dto.R; |
|||
import com.qs.serve.common.model.dto.SimpleKeyValue; |
|||
import com.qs.serve.common.model.enums.BizType; |
|||
import com.qs.serve.common.util.*; |
|||
import com.qs.serve.common.util.model.DateFormatString; |
|||
import com.qs.serve.controller.dto.SyLoginParam; |
|||
import com.qs.serve.modules.seeyon.SyKeyLoginUtil; |
|||
import com.qs.serve.modules.bms.service.BmsSupplierAddressService; |
|||
import com.qs.serve.modules.goods.entity.GoodsCategory; |
|||
import com.qs.serve.modules.goods.entity.GoodsSku; |
|||
import com.qs.serve.modules.goods.entity.GoodsSpu; |
|||
import com.qs.serve.modules.goods.mapper.GoodsImminentBatchMapper; |
|||
import com.qs.serve.modules.goods.service.GoodsCategoryRuleService; |
|||
import com.qs.serve.modules.goods.service.GoodsCategoryService; |
|||
import com.qs.serve.modules.goods.service.GoodsSkuService; |
|||
import com.qs.serve.modules.goods.service.GoodsSpuService; |
|||
import com.qs.serve.modules.oms.entity.OmsOrder; |
|||
import com.qs.serve.modules.oms.entity.OmsOrderItem; |
|||
import com.qs.serve.modules.oms.entity.OmsSaleOrder; |
|||
import com.qs.serve.modules.oms.entity.OmsSaleOrderItem; |
|||
import com.qs.serve.modules.oms.mapper.OmsOrderMapper; |
|||
import com.qs.serve.modules.oms.service.OmsOrderItemService; |
|||
import com.qs.serve.modules.oms.service.OmsOrderService; |
|||
import com.qs.serve.modules.oms.service.OmsSaleOrderItemService; |
|||
import com.qs.serve.modules.oms.service.OmsSaleOrderService; |
|||
import com.qs.serve.modules.seeyon.entity.SyAffairStateResult; |
|||
import com.qs.serve.modules.seeyon.enums.SyAffairState; |
|||
import com.qs.serve.modules.seeyon.service.SeeYonRequestService; |
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.modules.sys.entity.SysTenant; |
|||
import com.qs.serve.modules.sys.entity.SysUser; |
|||
import com.qs.serve.modules.sys.entity.dto.SysLoginByPhoneParam; |
|||
import com.qs.serve.modules.sys.entity.dto.SysLoginParam; |
|||
import com.qs.serve.modules.sys.entity.dto.SysResetPwdByPhoneParam; |
|||
import com.qs.serve.modules.sys.service.SysTenantService; |
|||
import com.qs.serve.modules.sys.service.SysUserLoginService; |
|||
import com.qs.serve.modules.sys.service.SysUserService; |
|||
import com.qs.serve.modules.tbs.common.TbsSeeYonConst; |
|||
import com.qs.serve.modules.tbs.entity.TbsActivity; |
|||
import com.qs.serve.modules.tbs.entity.TbsCostApply; |
|||
import com.qs.serve.modules.tbs.service.TbsActivityService; |
|||
import com.qs.serve.modules.tbs.service.TbsCostApplyService; |
|||
import com.qs.serve.modules.tzc.entity.TzcPolicy; |
|||
import com.qs.serve.modules.tzc.service.TzcPolicyService; |
|||
import com.qs.serve.modules.vtb.entity.VtbVerification; |
|||
import com.qs.serve.modules.vtb.entity.VtbVerificationBatch; |
|||
import com.qs.serve.modules.vtb.service.VtbVerificationBatchService; |
|||
import com.qs.serve.modules.vtb.service.VtbVerificationService; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import javax.validation.Valid; |
|||
import java.io.IOException; |
|||
import java.time.LocalDateTime; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
/** |
|||
* 门户:后台接口 |
|||
* @author YenHex |
|||
* @since 2022/3/2 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
@RestController |
|||
@RequestMapping("portal") |
|||
public class AdminPortalController { |
|||
|
|||
private SysTenantService sysTenantService; |
|||
private SysUserLoginService sysUserLoginService; |
|||
private RedisService redisService; |
|||
private SysUserService sysUserService; |
|||
private ProjectProperties projectProperties; |
|||
private SeeYonRequestService seeYonRequestService; |
|||
private TbsCostApplyService costApplyService; |
|||
private VtbVerificationService verificationService; |
|||
private VtbVerificationBatchService verificationBatchService; |
|||
private TzcPolicyService policyService; |
|||
private TbsActivityService activityService; |
|||
private GoodsImminentBatchMapper goodsImminentBatchMapper; |
|||
private OmsOrderMapper omsOrderMapper; |
|||
|
|||
private OmsOrderService omsOrderService; |
|||
private OmsOrderItemService omsOrderItemService; |
|||
|
|||
private OmsSaleOrderService omsSaleOrderService; |
|||
private OmsSaleOrderItemService omsSaleOrderItemService; |
|||
|
|||
private BmsSupplierAddressService bmsSupplierAddressService; |
|||
private GoodsCategoryRuleService goodsCategoryRuleService; |
|||
private GoodsSpuService goodsSpuService; |
|||
private GoodsSkuService goodsSkuService; |
|||
private GoodsCategoryService goodsCategoryService; |
|||
|
|||
@GetMapping("/getSystemTime") |
|||
public R<?> getSystemTime(){ |
|||
return R.ok(DateUtils.format(LocalDateTime.now(), DateFormatString.DATE_TIME)); |
|||
} |
|||
|
|||
/** |
|||
* 获取所有租户 |
|||
* @return |
|||
*/ |
|||
@GetMapping("/listTenant") |
|||
public R<List<SysTenant>> getList(){ |
|||
List<SysTenant> list = sysTenantService.list2(); |
|||
return R.ok(list); |
|||
} |
|||
|
|||
/** |
|||
* 致远远程跳转接口 |
|||
* @param param |
|||
* @param response |
|||
* @throws IOException |
|||
*/ |
|||
@GetMapping("/syKeyLogin") |
|||
public void getList(SyLoginParam param, HttpServletResponse response) throws IOException { |
|||
String templateCode = param.getTemplateCode(); |
|||
String syId = param.getSyId(); |
|||
|
|||
// dev remove
|
|||
if(!StringUtils.hasText(syId)){ |
|||
response.sendRedirect(projectProperties.getWebUrl()+"/#/login?"); |
|||
return; |
|||
} |
|||
|
|||
String key = param.getKey(); |
|||
SyAffairStateResult affairStateResult = seeYonRequestService.checkAffairState(key,syId,templateCode); |
|||
|
|||
// dev add
|
|||
//syId = affairStateResult.getMemberId();
|
|||
|
|||
if(affairStateResult.getState()==SyAffairState.error){ |
|||
response.sendRedirect(projectProperties.getWebUrl()+"/#/login?"); |
|||
return; |
|||
} |
|||
|
|||
//通过类型和key获取审批id
|
|||
String targetId = affairStateResult.getTargetId(); |
|||
String affairId = affairStateResult.getAffairId(); |
|||
String memberId = affairStateResult.getMemberId(); |
|||
|
|||
//通过syId生成token
|
|||
String token = sysUserLoginService.loginBySyUserId(syId); |
|||
if(token==null){ |
|||
response.sendRedirect(projectProperties.getWebUrl()+"/#/login?"); |
|||
return; |
|||
}else { |
|||
String jumpUrl = "404"; |
|||
SyAffairState affairState = affairStateResult.getState(); |
|||
if(affairState!=SyAffairState.none&&affairState!=SyAffairState.error){ |
|||
//判断是否当前人员
|
|||
if(syId.equals(memberId)){ |
|||
//待审列表
|
|||
if (affairState==SyAffairState.next){ |
|||
if(templateCode.equals(TbsSeeYonConst.BatchCostCheckConf.Code())){ |
|||
VtbVerificationBatch object = verificationBatchService.getById(targetId); |
|||
jumpUrl = SyKeyLoginUtil.getUnCheckedUrl4BatchVerification(object.getCostApplyId(),affairId,object.getId()); |
|||
}else if(templateCode.equals(TbsSeeYonConst.CostCheckConf.Code())){ |
|||
VtbVerification object = verificationService.getById(targetId); |
|||
TbsActivity activity = activityService.getById(object.getActivityId()); |
|||
jumpUrl = SyKeyLoginUtil.getPreCheckUrl4Verification(activity.getCostApplyId(),activity.getId(),object.getId(),affairId); |
|||
}else{ |
|||
jumpUrl = SyKeyLoginUtil.getPreCheckUrl(templateCode,targetId,affairId); |
|||
} |
|||
}else { |
|||
if(templateCode.equals(TbsSeeYonConst.BatchCostCheckConf.Code())){ |
|||
VtbVerificationBatch object = verificationBatchService.getById(targetId); |
|||
jumpUrl = SyKeyLoginUtil.getCheckedUrl4BatchVerification(object.getCostApplyId(),affairId,object.getId()); |
|||
}else if(templateCode.equals(TbsSeeYonConst.CostCheckConf.Code())){ |
|||
VtbVerification object = verificationService.getById(targetId); |
|||
TbsActivity activity = activityService.getById(object.getActivityId()); |
|||
jumpUrl = SyKeyLoginUtil.getCheckedDetailUrl4Verification(activity.getCostApplyId(),activity.getId(),object.getId()); |
|||
}else{ |
|||
jumpUrl = SyKeyLoginUtil.getCheckedDetailUrl(templateCode,targetId); |
|||
} |
|||
} |
|||
}else{ |
|||
//判断是否创建人,创建人则跳转到详情
|
|||
SysUser sysUser = sysUserService.getBySyId(syId); |
|||
String creator = null; |
|||
//非当前表单用户跳转到404页面
|
|||
if(templateCode.equals(TbsSeeYonConst.CostApplyConf.Code())){ |
|||
TbsCostApply object = costApplyService.getById(targetId); |
|||
creator = object.getCreateBy(); |
|||
}else if(templateCode.equals(TbsSeeYonConst.CostCheckConf.Code())){ |
|||
VtbVerification object = verificationService.getById(targetId); |
|||
creator = object.getCreateBy(); |
|||
}else if(templateCode.equals(TbsSeeYonConst.BatchCostCheckConf.Code())){ |
|||
VtbVerificationBatch object = verificationBatchService.getById(targetId); |
|||
creator = object.getCreateBy(); |
|||
}else if(templateCode.equals(TbsSeeYonConst.PolicyConf.Code())){ |
|||
TzcPolicy object = policyService.getById(targetId); |
|||
creator = object.getCreateBy(); |
|||
} |
|||
if(creator!=null&&creator.equals(sysUser.getId())){ |
|||
jumpUrl = SyKeyLoginUtil.getMyDetailUrl(templateCode,targetId); |
|||
} |
|||
} |
|||
} |
|||
String fontUrl = projectProperties.getWebUrl() + "/#/jump?code=001&token="+token+"&jumpTo="+jumpUrl; |
|||
log.warn("fontUrl:{}",fontUrl); |
|||
response.sendRedirect(fontUrl); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 登录接口 |
|||
* @return |
|||
*/ |
|||
@LimitSubmit |
|||
@SysLog(title = "人员",desc = "后台登录",biz = BizType.LOGIN,saveReqParam = false) |
|||
@PostMapping("/login") |
|||
public R<?> login(@RequestBody @Valid SysLoginParam param){ |
|||
return R.ok(sysUserLoginService.login(param)); |
|||
} |
|||
|
|||
/** |
|||
* 登录接口 |
|||
* @return |
|||
*/ |
|||
@PostMapping("/flushToken") |
|||
public R<?> flushToken(HttpServletRequest request){ |
|||
String token = request.getHeader(GySysConst.AUTHORIZATION_PROP); |
|||
String userId = JwtUtils.getUserId(token); |
|||
String client = JwtUtils.getClient(token); |
|||
String redisKey = StringUtils.format(RedisCacheKeys.LOGIN_KEY_APP,client,userId); |
|||
Map<String,Object> tokenMap = new HashMap<>(10); |
|||
String token2 = JwtUtils.generateToken(userId, LoginUserType.SYS_USER,client); |
|||
redisService.set(redisKey,token2); |
|||
tokenMap.put("token", token2); |
|||
tokenMap.put("client",client); |
|||
return R.ok(tokenMap); |
|||
} |
|||
|
|||
/** |
|||
* 手机登陆 |
|||
* @return |
|||
*/ |
|||
@LimitSubmit |
|||
@SysLog(title = "人员",desc = "手机登陆",biz = BizType.LOGIN,saveReqParam = false) |
|||
@PostMapping("/phoneLogin") |
|||
public R<?> phoneLogin(@RequestBody @Valid SysLoginByPhoneParam param){ |
|||
return R.ok(sysUserLoginService.login(param)); |
|||
} |
|||
|
|||
/** |
|||
* 登出接口 |
|||
* @return |
|||
*/ |
|||
@SysLog(title = "人员",desc = "退出登录",biz = BizType.LOGOUT,saveReqParam = false) |
|||
@GetMapping("/logout") |
|||
public R<?> login(){ |
|||
return R.ok(); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取用户手机验证码 |
|||
*/ |
|||
@LimitSubmit(interval = 10000,message = "请10秒后尝试") |
|||
@SysLog(title = "人员",desc = "获取用户手机验证码",biz = BizType.OTHER) |
|||
@GetMapping("/userPhoneCode/{phone}") |
|||
public R<?> phoneCode(@PathVariable("phone") String phone){ |
|||
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>(); |
|||
wrapper.eq(SysUser::getAccount,phone); |
|||
Long count = sysUserService.count(wrapper); |
|||
if(count<1L){ |
|||
return R.error("无效手机号,请重新输入"); |
|||
} |
|||
String key = RedisCacheKeys.PHONE_KEY+phone; |
|||
String code = redisService.getString(key); |
|||
if(code==null){ |
|||
code = IdUtil.genCode(6); |
|||
} |
|||
redisService.set(key,code,1, TimeUnit.MINUTES); |
|||
// send msg
|
|||
return R.ok(); |
|||
} |
|||
|
|||
/** |
|||
* 重置手机用户密码 |
|||
*/ |
|||
@LimitSubmit(interval = 10000,message = "请10秒后尝试") |
|||
@SysLog(title = "人员",desc = "重置手机用户密码",biz = BizType.RESET) |
|||
@PostMapping("/resetPwdByPhone") |
|||
public R<?> phoneCode(@RequestBody @Valid SysResetPwdByPhoneParam param){ |
|||
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>(); |
|||
wrapper.eq(SysUser::getAccount,param.getPhone()); |
|||
List<SysUser> userList = sysUserService.list(wrapper); |
|||
if(userList.size()<1){ |
|||
return R.error("无效手机号,请重新输入"); |
|||
} |
|||
String key = RedisCacheKeys.PHONE_KEY+param.getPhone(); |
|||
String code = redisService.getString(key); |
|||
if(!param.getCode().equals(code)){ |
|||
return R.error("验证码无效或过期"); |
|||
} |
|||
SysUser sysUser = new SysUser(); |
|||
sysUser.setId(userList.get(0).getId()); |
|||
sysUser.setPassword(SecureUtil.md5(param.getNewPwd())); |
|||
sysUserService.updateById(sysUser); |
|||
return R.ok(); |
|||
} |
|||
|
|||
/** |
|||
* 根据ID查询 |
|||
* @param id |
|||
* @return |
|||
*/ |
|||
@GetMapping("/getOrder/{id}") |
|||
public R<OmsOrder> getById(@PathVariable("id") String id,String supplierId){ |
|||
AuthContextUtils.setTenant("001"); |
|||
OmsOrder omsOrder = omsOrderService.getById(id); |
|||
if(omsOrder==null){return R.errorNotFound();} |
|||
omsOrder.setBrandRuleInfo(goodsCategoryRuleService.getById(omsOrder.getBrandRuleId())); |
|||
omsOrder.setAddressInfo(bmsSupplierAddressService.getById(omsOrder.getSupplierAddrId())); |
|||
|
|||
// 关联折扣信息
|
|||
if(StringUtils.hasText(omsOrder.getOaRateId())){ |
|||
SimpleKeyValue obj = omsOrderMapper.getExpiredRateInfo(omsOrder.getOaRateId()); |
|||
omsOrder.setDiscountRateInfo(obj); |
|||
} |
|||
if(omsOrder.getSupplierId().toString().equals(supplierId)){ |
|||
LambdaQueryWrapper<OmsOrderItem> lqw = new LambdaQueryWrapper<>(); |
|||
lqw.eq(OmsOrderItem::getOrderId,id); |
|||
List<OmsOrderItem> list = omsOrderItemService.list(lqw); |
|||
for (OmsOrderItem orderItem : list) { |
|||
GoodsSpu goodsSpu = goodsSpuService.getById(orderItem.getSpuId()); |
|||
GoodsCategory goodsCategory = goodsCategoryService.getById(goodsSpu.getCategoryLast()); |
|||
orderItem.setCategoryInfo(goodsCategory); |
|||
orderItem.setSpuInfo(goodsSpu); |
|||
GoodsSku goodsSku = goodsSkuService.getById(orderItem.getSkuId()); |
|||
if(goodsSku!=null){ |
|||
orderItem.setSkuSpecialFlag(goodsSku.getSpecialFlag()); |
|||
} |
|||
//临期品添加批次对象
|
|||
if(omsOrder.getOrderType().equals(3)&&orderItem.getSkuBatchId()!=null){ |
|||
orderItem.setBatchInfo(goodsImminentBatchMapper.selectById(orderItem.getSkuBatchId())); |
|||
} |
|||
} |
|||
omsOrder.setOrderItems(list); |
|||
return R.ok(omsOrder); |
|||
} |
|||
|
|||
return R.error(); |
|||
} |
|||
|
|||
/** |
|||
* 根据ID查询 |
|||
* @param id |
|||
* @return |
|||
*/ |
|||
@GetMapping("/getSaleOrder/{id}") |
|||
public R<OmsSaleOrder> getSaleOrderById(@PathVariable("id") String id, String supplierId){ |
|||
AuthContextUtils.setTenant("001"); |
|||
OmsSaleOrder omsOrder = omsSaleOrderService.getById(id); |
|||
if(omsOrder==null){return R.errorNotFound();} |
|||
omsOrder.setBrandRuleInfo(goodsCategoryRuleService.getById(omsOrder.getBrandRuleId())); |
|||
omsOrder.setAddressInfo(bmsSupplierAddressService.getById(omsOrder.getSupplierAddrId())); |
|||
|
|||
// 关联折扣信息
|
|||
if(StringUtils.hasText(omsOrder.getOaRateId())){ |
|||
SimpleKeyValue obj = omsOrderMapper.getExpiredRateInfo(omsOrder.getOaRateId()); |
|||
omsOrder.setDiscountRateInfo(obj); |
|||
} |
|||
if(omsOrder.getSupplierId().toString().equals(supplierId)){ |
|||
LambdaQueryWrapper<OmsSaleOrderItem> lqw = new LambdaQueryWrapper<>(); |
|||
lqw.eq(OmsSaleOrderItem::getOrderId,id); |
|||
List<OmsSaleOrderItem> list = omsSaleOrderItemService.list(lqw); |
|||
for (OmsSaleOrderItem orderItem : list) { |
|||
GoodsSpu goodsSpu = goodsSpuService.getById(orderItem.getSpuId()); |
|||
GoodsCategory goodsCategory = goodsCategoryService.getById(goodsSpu.getCategoryLast()); |
|||
orderItem.setCategoryInfo(goodsCategory); |
|||
orderItem.setSpuInfo(goodsSpu); |
|||
GoodsSku goodsSku = goodsSkuService.getById(orderItem.getSkuId()); |
|||
if(goodsSku!=null){ |
|||
orderItem.setSkuSpecialFlag(goodsSku.getSpecialFlag()); |
|||
} |
|||
//临期品添加批次对象
|
|||
if(omsOrder.getOrderType().equals(3)&&orderItem.getSkuBatchId()!=null){ |
|||
orderItem.setBatchInfo(goodsImminentBatchMapper.selectById(orderItem.getSkuBatchId())); |
|||
} |
|||
} |
|||
omsOrder.setOrderItems(list); |
|||
return R.ok(omsOrder); |
|||
} |
|||
return R.error(); |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,21 @@ |
|||
package com.qs.serve.controller; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
/** |
|||
* 门户:API通用接口 |
|||
* @author YenHex |
|||
* @since 2022/3/14 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/api/common") |
|||
public class CommonApi { |
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,120 @@ |
|||
package com.qs.serve.controller; |
|||
|
|||
import com.qs.serve.common.config.properties.UploadProperties; |
|||
import com.qs.serve.common.model.annotation.SysLog; |
|||
import com.qs.serve.common.model.dto.R; |
|||
import com.qs.serve.common.model.enums.BizType; |
|||
import com.qs.serve.common.util.IdUtil; |
|||
import com.qs.serve.common.util.JwtUtils; |
|||
import com.qs.serve.common.util.UploadUtil; |
|||
import com.qs.serve.modules.oss.service.OssService; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
import org.springframework.web.multipart.MultipartHttpServletRequest; |
|||
import org.springframework.web.util.WebUtils; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
import java.io.File; |
|||
import java.io.IOException; |
|||
import java.time.LocalDate; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 门户:后台通用接口 |
|||
* @author YenHex |
|||
* @since 2022/3/14 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/common") |
|||
public class CommonController { |
|||
|
|||
private UploadProperties uploadProperties; |
|||
|
|||
private OssService ossService; |
|||
|
|||
/** |
|||
* 获取签名 |
|||
* @param request |
|||
* @return |
|||
*/ |
|||
@GetMapping("/getSign") |
|||
public R getSign(HttpServletRequest request) { |
|||
return R.ok(ossService.getPolicySign()); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 单图上传 |
|||
* @apiNote file不能为空 |
|||
* @param request |
|||
* @return |
|||
*/ |
|||
@SysLog(title = "文件",biz = BizType.UPLOAD) |
|||
@PostMapping("/upload") |
|||
public R upload(HttpServletRequest request) { |
|||
String relativePath = UploadUtil.put(uploadProperties.getLogicalPath(),IdUtil.timeStampId(),request); |
|||
if(relativePath!=null){ |
|||
return R.ok(uploadProperties.getProxyUrl()+relativePath,"上传成功"); |
|||
} |
|||
return R.error("上传失败"); |
|||
} |
|||
|
|||
/** |
|||
* 验证token |
|||
* @param token |
|||
* @return |
|||
*/ |
|||
@PostMapping("/validToken") |
|||
public R validToken(String token) { |
|||
return R.isOk(JwtUtils.verify(token),"无效token"); |
|||
} |
|||
|
|||
/** |
|||
* 多图上传 |
|||
* @apiNote files不能为空 |
|||
* @param request |
|||
* @return |
|||
*/ |
|||
@SysLog(title = "文件",biz = BizType.UPLOAD) |
|||
@PostMapping( "/uploadMulti") |
|||
public R<?> multiUpload(HttpServletRequest request) { |
|||
String contentType = request.getContentType(); |
|||
List<MultipartFile> files = null; |
|||
if (contentType != null && contentType.toLowerCase().startsWith("multipart")) { |
|||
MultipartHttpServletRequest multipartHttpServletRequest = WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class); |
|||
files = multipartHttpServletRequest.getFiles("files"); |
|||
} |
|||
if (files==null||files.isEmpty()) { |
|||
return R.error("请选择文件"); |
|||
} |
|||
List<String> list = new ArrayList<>(); |
|||
for (int i = 0; i < files.size(); i++) { |
|||
MultipartFile file = files.get(i); |
|||
if (file.isEmpty()) { |
|||
return R.error("上传第" + (i++) + "个文件失败"); |
|||
} |
|||
String fileOrgName = file.getOriginalFilename(); |
|||
String mimeType = fileOrgName.substring(fileOrgName.lastIndexOf(".")); |
|||
String filePath = LocalDate.now().toString().replace("-","")+"/"+ IdUtil.timeStampId()+mimeType; |
|||
String uploadPath = uploadProperties.getLogicalPath(); |
|||
File dest = new File(uploadPath + filePath); |
|||
try { |
|||
file.transferTo(dest); |
|||
list.add(uploadProperties.getProxyUrl()+filePath); |
|||
} catch (IOException e) { |
|||
log.error(e.toString(), e); |
|||
return R.error("上传第" + (i++) + "个文件失败"); |
|||
} |
|||
} |
|||
return R.ok(list); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,122 @@ |
|||
package com.qs.serve.controller; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import me.chanjar.weixin.mp.api.WxMpMessageRouter; |
|||
import me.chanjar.weixin.mp.api.WxMpService; |
|||
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; |
|||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
/** |
|||
* 门户:微信公众号回调 |
|||
* @author YenHex |
|||
* @since 2022-03-07 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
//@RestController
|
|||
//@RequestMapping("/api/wx/mp/portal/{appid}")
|
|||
public class WxMpPortalApi { |
|||
|
|||
private final WxMpService wxService; |
|||
private final WxMpMessageRouter messageRouter; |
|||
|
|||
/** |
|||
* 校验身份 |
|||
* @param appid |
|||
* @param signature |
|||
* @param timestamp |
|||
* @param nonce |
|||
* @param echostr |
|||
* @return |
|||
*/ |
|||
@GetMapping(produces = "text/plain;charset=utf-8") |
|||
public String authGet(@PathVariable String appid, |
|||
@RequestParam(name = "signature", required = false) String signature, |
|||
@RequestParam(name = "timestamp", required = false) String timestamp, |
|||
@RequestParam(name = "nonce", required = false) String nonce, |
|||
@RequestParam(name = "echostr", required = false) String echostr) { |
|||
|
|||
log.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature, |
|||
timestamp, nonce, echostr); |
|||
if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) { |
|||
throw new IllegalArgumentException("请求参数非法,请核实!"); |
|||
} |
|||
if (!this.wxService.switchover(appid)) { |
|||
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid)); |
|||
} |
|||
if (wxService.checkSignature(timestamp, nonce, signature)) { |
|||
return echostr; |
|||
} |
|||
return "非法请求"; |
|||
} |
|||
|
|||
/** |
|||
* 身份校验2 |
|||
* @param appid |
|||
* @param requestBody |
|||
* @param signature |
|||
* @param timestamp |
|||
* @param nonce |
|||
* @param openid |
|||
* @param encType |
|||
* @param msgSignature |
|||
* @return |
|||
*/ |
|||
@PostMapping(produces = "application/xml; charset=UTF-8") |
|||
public String post(@PathVariable String appid, |
|||
@RequestBody String requestBody, |
|||
@RequestParam("signature") String signature, |
|||
@RequestParam("timestamp") String timestamp, |
|||
@RequestParam("nonce") String nonce, |
|||
@RequestParam("openid") String openid, |
|||
@RequestParam(name = "encrypt_type", required = false) String encType, |
|||
@RequestParam(name = "msg_signature", required = false) String msgSignature) { |
|||
log.info("\n接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}]," |
|||
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", |
|||
openid, signature, encType, msgSignature, timestamp, nonce, requestBody); |
|||
if (!this.wxService.switchover(appid)) { |
|||
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid)); |
|||
} |
|||
|
|||
if (!wxService.checkSignature(timestamp, nonce, signature)) { |
|||
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!"); |
|||
} |
|||
String out = null; |
|||
if (encType == null) { |
|||
// 明文传输的消息
|
|||
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody); |
|||
WxMpXmlOutMessage outMessage = this.route(inMessage); |
|||
if (outMessage == null) { |
|||
return ""; |
|||
} |
|||
out = outMessage.toXml(); |
|||
} else if ("aes".equalsIgnoreCase(encType)) { |
|||
// aes加密的消息
|
|||
WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(), |
|||
timestamp, nonce, msgSignature); |
|||
log.debug("\n消息解密后内容为:\n{} ", inMessage.toString()); |
|||
WxMpXmlOutMessage outMessage = this.route(inMessage); |
|||
if (outMessage == null) { |
|||
return ""; |
|||
} |
|||
|
|||
out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage()); |
|||
} |
|||
|
|||
log.debug("\n组装回复信息:{}", out); |
|||
return out; |
|||
} |
|||
|
|||
private WxMpXmlOutMessage route(WxMpXmlMessage message) { |
|||
try { |
|||
return this.messageRouter.route(message); |
|||
} catch (Exception e) { |
|||
log.error("路由消息时出现异常!", e); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,237 @@ |
|||
package com.qs.serve.controller; |
|||
|
|||
import com.qs.serve.common.framework.redis.RedisService; |
|||
import com.qs.serve.common.framework.security.model.LoginUser; |
|||
import com.qs.serve.common.framework.security.model.LoginUserType; |
|||
import com.qs.serve.common.model.annotation.SysLog; |
|||
import com.qs.serve.common.model.consts.RedisCacheKeys; |
|||
import com.qs.serve.common.model.dto.R; |
|||
import com.qs.serve.common.model.enums.BizType; |
|||
import com.qs.serve.common.model.enums.HttpCode; |
|||
import com.qs.serve.common.model.enums.InterType; |
|||
import com.qs.serve.common.util.*; |
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.modules.sys.mapper.SysTenantMapper; |
|||
import com.qs.serve.modules.sys.service.SysUserService; |
|||
import com.qs.serve.modules.sys.service.impl.SysUserDetailsServiceImpl; |
|||
import com.qs.serve.modules.wx.common.conf.WxCpConfig; |
|||
import com.qs.serve.modules.wx.entity.WxApp; |
|||
import com.qs.serve.modules.wx.entity.WxUser; |
|||
import com.qs.serve.modules.wx.entity.dto.WxLoginUser; |
|||
import com.qs.serve.modules.wx.service.WxAppService; |
|||
import com.qs.serve.modules.wx.service.WxUserService; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import me.chanjar.weixin.common.error.WxErrorException; |
|||
import me.chanjar.weixin.cp.api.WxCpService; |
|||
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; |
|||
import me.chanjar.weixin.cp.bean.WxCpAgentJsapiSignature; |
|||
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl; |
|||
import org.jetbrains.annotations.NotNull; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.validation.Valid; |
|||
import java.util.ArrayList; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 门户:微信登录 |
|||
* @author YenHex |
|||
* @since 2022/3/7 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/api/wx/login") |
|||
public class WxSvcLoginApi { |
|||
|
|||
private final WxUserService wxUserService; |
|||
|
|||
private final RedisService redisService; |
|||
|
|||
private final SysUserDetailsServiceImpl userDetailsService; |
|||
|
|||
private final SysTenantMapper sysTenantMapper; |
|||
private final WxAppService wxAppService; |
|||
private SysUserService sysUserService; |
|||
|
|||
/** |
|||
* 企业微信登录 |
|||
* @param wxLoginUser |
|||
* @param request |
|||
* @return |
|||
*/ |
|||
@SysLog(title = "企业微信登录",biz = BizType.LOGIN,inter = InterType.API) |
|||
@PostMapping("/cp") |
|||
public R<?> loginCompanyApp(@RequestBody @Valid WxLoginUser wxLoginUser, HttpServletRequest request){ |
|||
WxUser wxUser = null; |
|||
try { |
|||
wxUser = wxUserService.login(wxLoginUser,request); |
|||
} catch (Exception e) { |
|||
Assert.throwEx(e.getMessage()); |
|||
} |
|||
if(wxUser==null){ |
|||
Assert.throwEx(HttpCode.WX_ERR); |
|||
} |
|||
Map<String, Object> objectMap = genTokenInfo(request, wxUser); |
|||
return R.ok(objectMap); |
|||
} |
|||
|
|||
/** |
|||
* 获取签名授权 |
|||
* @param url |
|||
* @param request |
|||
* @return |
|||
*/ |
|||
@GetMapping("/getCpSignature") |
|||
public R<WxCpAgentJsapiSignature> getCpSignature(String url, HttpServletRequest request) { |
|||
AuthContextUtils.setTenant("001"); |
|||
String agentIdStr = request.getHeader("agentId"); |
|||
String appId = AuthContextUtils.getAppId(); |
|||
WxApp wxApp = wxAppService.getById(appId); |
|||
Integer agentId = Integer.parseInt(agentIdStr); |
|||
// 企业微信登录
|
|||
WxCpService wxCpService = new WxCpServiceImpl(); |
|||
WxCpDefaultConfigImpl config =new WxCpDefaultConfigImpl(); |
|||
config.setAgentId(agentId); |
|||
config.setCorpSecret(WxCpConfig.getSecret(agentId)); |
|||
config.setCorpId(wxApp.getId()); |
|||
wxCpService.setWxCpConfigStorage(config); |
|||
WxCpAgentJsapiSignature signature = null; |
|||
try { |
|||
signature = wxCpService.createAgentJsapiSignature(url); |
|||
} catch (WxErrorException e) { |
|||
log.warn("企业微信签名授权失败:appid{},agentId:{},{}",appId,agentId,e.getMessage()); |
|||
} |
|||
return R.ok(signature); |
|||
} |
|||
|
|||
/** |
|||
* 企业微信登录 |
|||
* @param wxLoginUser |
|||
* @param request |
|||
* @return |
|||
*/ |
|||
@SysLog(title = "企业微信登录",biz = BizType.LOGIN,inter = InterType.API) |
|||
@PostMapping("/cp4Pc") |
|||
public R<?> loginCompanyPc(@RequestBody @Valid WxLoginUser wxLoginUser, HttpServletRequest request){ |
|||
WxUser wxUser = null; |
|||
try { |
|||
wxUser = wxUserService.login(wxLoginUser,request); |
|||
} catch (Exception e) { |
|||
Assert.throwEx(e.getMessage()); |
|||
} |
|||
if(wxUser==null){ |
|||
Assert.throwEx(HttpCode.WX_ERR); |
|||
} |
|||
Map<String, Object> objectMap = genTokenInfo(request, wxUser); |
|||
return R.ok(objectMap.get("adminTokenInfo")); |
|||
} |
|||
|
|||
/** |
|||
* 小程序登陆(暂测试) |
|||
* @param wxLoginUser |
|||
* @param request |
|||
* @return |
|||
*/ |
|||
@SysLog(title = "小程序登录",biz = BizType.LOGIN,inter = InterType.API) |
|||
@PostMapping("/ma") |
|||
public R<?> loginMicroApp(@RequestBody @Valid WxLoginUser wxLoginUser, HttpServletRequest request){ |
|||
WxUser wxUser = null; |
|||
try { |
|||
wxUser = wxUserService.login(wxLoginUser,request); |
|||
} catch (Exception e) { |
|||
log.warn(e.getMessage()); |
|||
} |
|||
if(wxUser==null){ |
|||
Assert.throwEx(HttpCode.WX_ERR); |
|||
} |
|||
Map<String, Object> objectMap = genTokenInfo(request, wxUser); |
|||
return R.ok(objectMap); |
|||
} |
|||
|
|||
/** |
|||
* 公众号登录 |
|||
* @param wxLoginUser |
|||
* @return |
|||
* @throws Exception |
|||
*/ |
|||
@SysLog(title = "公众号登录",biz = BizType.LOGIN,inter = InterType.API) |
|||
@PostMapping("/mp") |
|||
public R<?> login(@RequestBody @Valid WxLoginUser wxLoginUser, HttpServletRequest request){ |
|||
WxUser wxUser = null; |
|||
try { |
|||
wxUser = wxUserService.login(wxLoginUser,request); |
|||
} catch (Exception e) { |
|||
log.warn(e.getMessage()); |
|||
} |
|||
if(wxUser==null){ |
|||
Assert.throwEx(HttpCode.WX_ERR); |
|||
} |
|||
Map<String, Object> objectMap = genTokenInfo(request, wxUser); |
|||
return R.ok(objectMap); |
|||
} |
|||
|
|||
@NotNull |
|||
private Map<String, Object> genTokenInfo(HttpServletRequest request, WxUser wxUser) { |
|||
Map<String,Object> objectMap = new HashMap<>(); |
|||
String token = IdUtil.fastSimpleUUID(); |
|||
LoginUser loginUser = new LoginUser(wxUser.getId(), wxUser.getEmpName(),"", |
|||
ServletUtils.getIp(request), LoginUserType.APP_USER,new ArrayList<>(),null,AuthContextUtils.getTenant()); |
|||
objectMap.put("token",token); |
|||
//微信登录ID
|
|||
String wxUserKey = StringUtils.format(RedisCacheKeys.WX_KEY_USER,token); |
|||
redisService.set(wxUserKey, wxUser.getId()); |
|||
//后台管理员信息
|
|||
Map<String,Object> tokenMap = new HashMap<>(10); |
|||
String client = "wx_app"; |
|||
String redisKey = StringUtils.format(RedisCacheKeys.LOGIN_KEY_APP,client, wxUser.getSysUserId()); |
|||
String pctoken = JwtUtils.generateToken(wxUser.getSysUserId(),loginUser.getTypeFlag(),client); |
|||
redisService.set(redisKey,pctoken); |
|||
tokenMap.put("token", pctoken); |
|||
tokenMap.put("userId", wxUser.getSysUserId()); |
|||
tokenMap.put("IP", loginUser.getLoginIp()); |
|||
tokenMap.put("tenant", sysTenantMapper.selectById(loginUser.getTenant())); |
|||
tokenMap.put("loginType",client); |
|||
tokenMap.put("client",client); |
|||
//关联
|
|||
objectMap.put("adminTokenInfo",tokenMap); |
|||
return objectMap; |
|||
} |
|||
|
|||
/** |
|||
* 公众号测试登录 |
|||
*/ |
|||
@PostMapping("/mptest") |
|||
public R<?> login(HttpServletRequest request){ |
|||
Map<String,Object> objectMap = new HashMap<>(); |
|||
String token = IdUtil.fastSimpleUUID(); |
|||
//微信登录ID
|
|||
String wxUserKey = StringUtils.format(RedisCacheKeys.WX_KEY_USER,token); |
|||
redisService.set(wxUserKey,"1"); |
|||
|
|||
LoginUser loginUser = new LoginUser("1","微信测试用户","", |
|||
ServletUtils.getIp(request), LoginUserType.APP_USER,new ArrayList<>(),null,AuthContextUtils.getTenant()); |
|||
objectMap.put("token",token); |
|||
String sysUserId = "1"; |
|||
Map<String,Object> tokenMap = new HashMap<>(10); |
|||
String client = "wx_app"; |
|||
String redisKey = StringUtils.format(RedisCacheKeys.LOGIN_KEY_APP,client,sysUserId); |
|||
String pctoken = JwtUtils.generateToken(sysUserId,loginUser.getTypeFlag(),client); |
|||
redisService.set(redisKey,pctoken); |
|||
tokenMap.put("token", pctoken); |
|||
tokenMap.put("userId", sysUserId); |
|||
tokenMap.put("IP", loginUser.getLoginIp()); |
|||
tokenMap.put("tenant", sysTenantMapper.selectById(loginUser.getTenant())); |
|||
tokenMap.put("loginType",client); |
|||
tokenMap.put("client",client); |
|||
//关联
|
|||
objectMap.put("adminTokenInfo",tokenMap); |
|||
return R.ok(objectMap); |
|||
} |
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,27 @@ |
|||
package com.qs.serve.controller.dto; |
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/5/13 |
|||
*/ |
|||
@Data |
|||
public class CounterResultVo { |
|||
|
|||
/** |
|||
* 待处理审批数 |
|||
*/ |
|||
private Long apprCounter; |
|||
|
|||
/** |
|||
* 公告未读数 |
|||
*/ |
|||
private Integer noticeCounter; |
|||
|
|||
/** |
|||
* 维修任务数 |
|||
*/ |
|||
private Long repairCounter; |
|||
|
|||
} |
@ -0,0 +1,27 @@ |
|||
package com.qs.serve.controller.dto; |
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/6/8 |
|||
*/ |
|||
@Data |
|||
public class SyLoginParam { |
|||
|
|||
/** |
|||
* 模板编码 |
|||
*/ |
|||
private String templateCode; |
|||
|
|||
/** |
|||
* 表单data的exsp5字段值 |
|||
*/ |
|||
private String key; |
|||
|
|||
/** |
|||
* 致远员工id |
|||
*/ |
|||
private String syId; |
|||
|
|||
} |
@ -0,0 +1,52 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.modules.bir.controller.BirActivityCenterGoodsController; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/11/7 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
@AllArgsConstructor |
|||
@ConditionalOnProperty(value = "project.bir-service-sync", havingValue = "true") |
|||
public class BirTask { |
|||
|
|||
private final BirActivityCenterGoodsController birActivityCenterGoodsController; |
|||
|
|||
/** |
|||
* 同步bir实时 |
|||
* 15分钟执行一次 |
|||
*/ |
|||
@Scheduled(cron="0 0/15 * * * ?") |
|||
public void toSyncBirEcro(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
birActivityCenterGoodsController.toSyncBirEcro(); |
|||
log.warn("bir更新完成"); |
|||
} |
|||
|
|||
/** |
|||
* 移除因作废的费用申请导致的bir数据 |
|||
* 每天中午13点触发 |
|||
*/ |
|||
@Scheduled(cron="0 0 13 * * ?") |
|||
public void toSyncRm(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
birActivityCenterGoodsController.toSyncRm(); |
|||
log.warn("bir更新完成 - 作废的费用"); |
|||
} |
|||
|
|||
@PostConstruct |
|||
void started() { |
|||
log.warn("bir同步开启"); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,48 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.modules.bms.controller.BmsRegion2Controller; |
|||
import com.qs.serve.modules.bms.controller.BmsRegionController; |
|||
import com.qs.serve.modules.tbs.service.TbsActivityTemplateService; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2024/5/9 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
@AllArgsConstructor |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class BmsTask { |
|||
|
|||
private final BmsRegion2Controller bmsRegion2Controller; |
|||
private final BmsRegionController bmsRegionController; |
|||
private final TbsActivityTemplateService tbsActivityTemplateService; |
|||
|
|||
/** |
|||
* 更新树路径 |
|||
*/ |
|||
@Scheduled(cron="0 0 7,13 * * ?") |
|||
public void levelTask(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
bmsRegionController.updateLevel(); |
|||
bmsRegion2Controller.updateLevel(); |
|||
//更新客户的关联区域的列
|
|||
tbsActivityTemplateService.updateState(); |
|||
} |
|||
|
|||
/** |
|||
* 5分钟执行一次 |
|||
*/ |
|||
@Scheduled(cron="0 0/5 * * * ?") |
|||
public void updateActTmpState(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
tbsActivityTemplateService.updateState(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,32 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.modules.bir.mapper.BirReportAccountBookMapper; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/7/14 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
@AllArgsConstructor |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class ErpDipatchTask { |
|||
|
|||
private final BirReportAccountBookMapper birReportAccountBookMapper; |
|||
|
|||
@Scheduled(cron="0 0 1 * * ?") |
|||
public void buildTempTable(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
birReportAccountBookMapper.buildAllDispatch(); |
|||
birReportAccountBookMapper.buildRegionDispatch(); |
|||
birReportAccountBookMapper.buildBizRegionDispatch(); |
|||
birReportAccountBookMapper.buildCustomerDispatch(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,60 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.modules.goods.service.GoodsApplicationService; |
|||
import com.qs.serve.modules.goods.service.GoodsCustomerPriceService; |
|||
import com.qs.serve.modules.goods.service.GoodsSpuService; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/12/20 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
@AllArgsConstructor |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class GoodsTask { |
|||
|
|||
private GoodsSpuService goodsSpuService; |
|||
private GoodsApplicationService goodsApplicationService; |
|||
private GoodsCustomerPriceService goodsCustomerPriceService; |
|||
|
|||
@Scheduled(cron="0 0 1 * * ?") |
|||
public void buildTempTable(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
goodsSpuService.initSkuNum(); |
|||
} |
|||
|
|||
/** |
|||
* 每15分钟同步一次 |
|||
*/ |
|||
@Scheduled(cron="0/15 0 0 * * ?") |
|||
public void syncCusPriceGoods(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
goodsCustomerPriceService.syncCustomerPrice(); |
|||
} |
|||
|
|||
/** |
|||
* 每两个小时同步一次 |
|||
*/ |
|||
//@Scheduled(cron="0 0/2 0 * * ?")
|
|||
public void syncStandGoods(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
goodsApplicationService.syncStandGoods(false); |
|||
} |
|||
|
|||
/** |
|||
* 同步价格 |
|||
*/ |
|||
//@Scheduled(cron="0 0 1 * * ?")
|
|||
public void syncInvPrice(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
goodsApplicationService.syncSkuPrice(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,59 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import com.qs.serve.common.framework.redis.RedisService; |
|||
import com.qs.serve.common.model.consts.RedisCacheKeys; |
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.modules.his.service.HisUserSupplierTempService; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.time.Duration; |
|||
import java.time.LocalDateTime; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/5/31 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
@AllArgsConstructor |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class HisTask { |
|||
|
|||
RedisService redisService; |
|||
HisUserSupplierTempService tempService; |
|||
|
|||
/** |
|||
* 数据处理10-15分钟,每隔20分钟执行一次,串行 |
|||
*/ |
|||
@Scheduled(cron="0 0/20 * * * ?") |
|||
public void buildTempTable(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
Integer opt = redisService.getInteger(RedisCacheKeys.HIS_UPDATE); |
|||
//设置默认值
|
|||
if (opt==null){ |
|||
redisService.set(RedisCacheKeys.HIS_UPDATE,0); |
|||
return; |
|||
} |
|||
//忽略状态
|
|||
if (opt==1){ |
|||
//执行同步
|
|||
log.warn("======================执行同步======================"); |
|||
LocalDateTime s1 = LocalDateTime.now(); |
|||
//防卡死,加入超时
|
|||
redisService.set(RedisCacheKeys.HIS_UPDATE,2,1, TimeUnit.HOURS); |
|||
tempService.reloadHis(); |
|||
LocalDateTime s2 = LocalDateTime.now(); |
|||
long diff = Duration.between(s1, s2).getSeconds(); |
|||
tempService.selectInfoHis(); |
|||
redisService.set(RedisCacheKeys.HIS_UPDATE,0); |
|||
log.warn("======================执行同步完成,耗时[ {} 秒]======================",diff); |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,36 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.modules.oms.mapper.OmsSaleOrderItemMapper; |
|||
import com.qs.serve.modules.oms.service.OmsOrderOptionsService; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2024/9/26 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
@AllArgsConstructor |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class OmsTask { |
|||
|
|||
OmsOrderOptionsService omsOrderOptionsService; |
|||
OmsSaleOrderItemMapper omsSaleOrderItemMapper; |
|||
|
|||
/** |
|||
* 同步临期品到调度系统的订单中间表 |
|||
* 每10分钟执行一次 |
|||
*/ |
|||
@Scheduled(cron="0 0/10 * * * ?") |
|||
public void saveToErpOrder(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
omsSaleOrderItemMapper.updateItemSkuBelong(); |
|||
omsOrderOptionsService.syncToErp(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,110 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.qs.serve.common.config.properties.ProjectApisProperties; |
|||
import com.qs.serve.common.model.AmountDTO; |
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.common.util.HttpUtil; |
|||
import com.qs.serve.modules.pay.mapper.PayPaymentItemMapper; |
|||
import com.qs.serve.modules.pay.mapper.PayPaymentMapper; |
|||
import com.qs.serve.modules.tbs.entity.TbsCostApply; |
|||
import com.qs.serve.modules.tbs.service.TbsCostApplyService; |
|||
import com.qs.serve.modules.vtb.mapper.VtbVerificationMapper; |
|||
import com.qs.serve.modules.vtb.service.VtbVerificationService; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/11/7 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
@AllArgsConstructor |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class PayTask { |
|||
|
|||
private VtbVerificationService vtbVerificationService; |
|||
private VtbVerificationMapper vtbVerificationMapper; |
|||
private final TbsCostApplyService costApplyService; |
|||
private final PayPaymentItemMapper payPaymentItemMapper; |
|||
private final PayPaymentMapper payPaymentMapper; |
|||
private ProjectApisProperties projectApisProperties; |
|||
|
|||
/** |
|||
* 将未支付的重新发起请求 |
|||
*/ |
|||
@Scheduled(cron="0 0 2 * * ?") |
|||
public void checkToPay(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
//预先调用伟成同步状态接口,减少查询记录数
|
|||
String url = projectApisProperties.getCheckPayStatus(); |
|||
HttpUtil.doGet(url,null); |
|||
List<Long> vids = vtbVerificationMapper.listNotPayVerifyIds(); |
|||
for (Long vid : vids) { |
|||
vtbVerificationService.toPayRequest(vid); |
|||
try { |
|||
Thread.sleep(200); |
|||
} catch (InterruptedException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
HttpUtil.doGet(url,null); |
|||
} |
|||
|
|||
/** |
|||
* 同步支付 |
|||
*/ |
|||
@Scheduled(cron="0 0 2 * * ?") |
|||
public void syncCostPayStatus(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
List<Long> costIds4State = payPaymentMapper.selectCostApplyIds4State(); |
|||
LambdaQueryWrapper<TbsCostApply> costLqw = new LambdaQueryWrapper<>(); |
|||
costLqw.select( |
|||
TbsCostApply::getId, |
|||
TbsCostApply::getTotalActivityAmount |
|||
); |
|||
costLqw.in(TbsCostApply::getId,costIds4State); |
|||
List<TbsCostApply> costApplyList = costApplyService.list(costLqw); |
|||
List<String> costIds = costApplyList.stream().map(TbsCostApply::toString).collect(Collectors.toList()); |
|||
|
|||
List<AmountDTO> amountDTOList = payPaymentItemMapper.selectCostTotal(costIds); |
|||
List<TbsCostApply> updatePayStateList = new ArrayList<>(); |
|||
for (TbsCostApply costApply : costApplyList) { |
|||
String costId = costApply.getId().toString(); |
|||
for (AmountDTO dto : amountDTOList) { |
|||
if(costId.equals(dto.getId())){ |
|||
BigDecimal totalPay = dto.getAmount(); |
|||
if(totalPay.compareTo(BigDecimal.ZERO)==0){ |
|||
//未支付忽略
|
|||
continue; |
|||
} |
|||
BigDecimal totalCost = costApply.getTotalActivityAmount(); |
|||
TbsCostApply updParam = new TbsCostApply(); |
|||
updParam.setId(costApply.getId()); |
|||
if(totalPay.compareTo(totalCost)<0){ |
|||
updParam.setPayStatus(1); |
|||
}else { |
|||
updParam.setPayStatus(2); |
|||
} |
|||
updatePayStateList.add(updParam); |
|||
} |
|||
} |
|||
} |
|||
costApplyService.updateBatchById(updatePayStateList); |
|||
//更新支付表记录,用于实现增量更新
|
|||
List<Long> costIds4Update = updatePayStateList.stream().map(TbsCostApply::getId).collect(Collectors.toList()); |
|||
if(costIds4Update.size()>0){ |
|||
payPaymentItemMapper.updateSyncCostState(costIds4Update); |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,47 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.modules.sys.service.SysPostService; |
|||
import com.qs.serve.task.controller.TaskUserController; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/6/27 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
@AllArgsConstructor |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class SysTask { |
|||
|
|||
TaskUserController taskUserController; |
|||
SysPostService sysPostService; |
|||
|
|||
/** |
|||
* 同步用户 |
|||
*/ |
|||
@Scheduled(cron="0 0 1 * * ?") |
|||
public void task1(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
taskUserController.test(); |
|||
//更新下属数据
|
|||
sysPostService.flushPathIds(); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 同步离职 |
|||
*/ |
|||
@Scheduled(cron="0 0 2 * * ?") |
|||
public void task2(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
taskUserController.doLeave(); |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,30 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import com.qs.serve.modules.tag.mapper.TagDataMapper; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/5/31 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
@AllArgsConstructor |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class TagTask { |
|||
|
|||
private TagDataMapper tagDataMapper; |
|||
|
|||
/** |
|||
* 数据处理10-15分钟,清理过期数据 |
|||
*/ |
|||
//@Scheduled(cron="0 0/1 * * * ?")
|
|||
public void buildTempTable(){ |
|||
//tagDataMapper.deleteExpireData();
|
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,74 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.modules.bir.mapper.BirTbsVtbPayJoinMapper; |
|||
import com.qs.serve.modules.tbs.common.TbsCostApplyState; |
|||
import com.qs.serve.modules.tbs.entity.TbsCostApply; |
|||
import com.qs.serve.modules.tbs.service.TbsActivityService; |
|||
import com.qs.serve.modules.tbs.service.TbsActivityTemplateService; |
|||
import com.qs.serve.modules.tbs.service.TbsCostApplyService; |
|||
import com.qs.serve.modules.vtb.service.VtbVerificationService; |
|||
import lombok.AllArgsConstructor; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.util.List; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/12/9 |
|||
*/ |
|||
@Component |
|||
@AllArgsConstructor |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class TbsTask { |
|||
|
|||
private final BirTbsVtbPayJoinMapper birTbsVtbPayJoinMapper; |
|||
private final TbsActivityService activityService; |
|||
private final TbsCostApplyService tbsCostApplyService; |
|||
private final TbsActivityTemplateService activityTemplateService; |
|||
private final VtbVerificationService vtbVerificationService; |
|||
|
|||
|
|||
//每日更新过期的活动,过期则进行冻结
|
|||
@Scheduled(cron="0 0 1 * * ?") |
|||
public void task1(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
activityService.initReopenState(); |
|||
|
|||
LambdaQueryWrapper<TbsCostApply> lqwApply = new LambdaQueryWrapper<>(); |
|||
lqwApply.select(TbsCostApply::getId); |
|||
lqwApply.eq(TbsCostApply::getChargeState, TbsCostApplyState.State_2_actioning.getCode()); |
|||
List<TbsCostApply> costApplyList = tbsCostApplyService.list(lqwApply); |
|||
List<Long> costApplyIds = costApplyList.stream().map(TbsCostApply::getId).collect(Collectors.toList()); |
|||
// 更新费用申请的活动的冻结状态
|
|||
activityService.flushBandingState(costApplyIds); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 每半小时执行一次 |
|||
*/ |
|||
@Scheduled(cron="0 0/30 * * * ?") |
|||
public void updateCheckState(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
tbsCostApplyService.updateCheckState(); |
|||
//间隔几个月换一次即可
|
|||
Long maxCostId = 313000L; |
|||
birTbsVtbPayJoinMapper.updateActivityAllCenters(maxCostId); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 每半小时执行一次 |
|||
*/ |
|||
@Scheduled(cron="0 0/30 * * * ?") |
|||
public void syncPayToErp(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
vtbVerificationService.toPayRequest(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,51 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.modules.seeyon.service.XiaoLuTonService; |
|||
import com.qs.serve.modules.third.service.PortalOfCostApplication; |
|||
import com.qs.serve.modules.tzc.common.TzPolicyItemStatus; |
|||
import com.qs.serve.modules.tzc.entity.TzcPolicyItem; |
|||
import com.qs.serve.modules.tzc.service.TzcPolicyApplicationService; |
|||
import com.qs.serve.modules.tzc.service.TzcPolicyItemService; |
|||
import com.qs.serve.modules.tzc.service.TzcPolicyService; |
|||
import lombok.AllArgsConstructor; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 政策同步方法 |
|||
* @author YenHex |
|||
* @since 2023/3/11 |
|||
*/ |
|||
@Component |
|||
@AllArgsConstructor |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class TzcPolicyTask { |
|||
|
|||
private TzcPolicyService policyService; |
|||
private TzcPolicyItemService policyItemService; |
|||
private TzcPolicyApplicationService policyApplicationService; |
|||
private PortalOfCostApplication portalOfCostApplication; |
|||
private XiaoLuTonService xiaoLuTonService; |
|||
|
|||
|
|||
/** |
|||
* 同步政策到销路通 |
|||
*/ |
|||
@Scheduled(cron="0 20 * * * ?") |
|||
public void syncPolicyToXlt(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
LambdaQueryWrapper<TzcPolicyItem> itemLqw = new LambdaQueryWrapper<>(); |
|||
itemLqw.select(TzcPolicyItem::getId); |
|||
itemLqw.eq(TzcPolicyItem::getPolicyItemStatus,TzPolicyItemStatus.Status_1_PassSuccess); |
|||
List<TzcPolicyItem> policyItemList = policyItemService.list(itemLqw); |
|||
for (TzcPolicyItem policyItem : policyItemList) { |
|||
policyApplicationService.syncPolicyItem(policyItem.getId()); |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,35 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/11/7 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
@AllArgsConstructor |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class TzcTask { |
|||
|
|||
|
|||
/** |
|||
* 同步未同步的政策项(排查数据,并无异常) |
|||
* 流程如下 |
|||
* 1.查询CMS未同步的政策项编码发送到中间服务 SELECT * FROM `tzc_policy` LEFT JOIN tzc_policy_item |
|||
* ON tzc_policy.id = tzc_policy_item.policy_id WHERE tzc_policy.del_flag = 0 AND tzc_policy_item.del_flag = 0 |
|||
* AND tzc_policy.policy_status = 2 AND tzc_policy_item.sync_status = 0 |
|||
* 2.中间服务返回已有的政策项编码 SELECT * FROM [dbo].[XLT_BI_GhDbf] where cGhMemo = '数据自动导入' and cGhCode like 'P%' |
|||
* 3.更新已有的政策项编码 update tzc_policy_item set sync_status = 1 where policy_item_code in (...) |
|||
* 4.重新请求未同步的政策编码 |
|||
* |
|||
*/ |
|||
//@Scheduled(cron="0 0 3 * * ?")
|
|||
public void checkToPay(){ |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,24 @@ |
|||
package com.qs.serve.task; |
|||
|
|||
import com.qs.serve.modules.sys.common.AuthContextUtils; |
|||
import com.qs.serve.modules.wx.service.WxUserService; |
|||
import lombok.AllArgsConstructor; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/9/26 |
|||
*/ |
|||
@Component |
|||
@AllArgsConstructor |
|||
public class WxUserTask { |
|||
|
|||
private WxUserService wxUserService; |
|||
|
|||
//@Scheduled(cron = "0 0/30 * * * ?")
|
|||
public void syncSubscribe(){ |
|||
AuthContextUtils.setTenant("001"); |
|||
wxUserService.syncSubscribe(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,60 @@ |
|||
package com.qs.serve.task.controller; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.qs.serve.common.config.DevEnvironmentConfig; |
|||
import com.qs.serve.common.framework.redis.RedisService; |
|||
import com.qs.serve.common.model.consts.RedisCacheKeys; |
|||
import com.qs.serve.common.model.dto.PageVo; |
|||
import com.qs.serve.common.model.dto.R; |
|||
import com.qs.serve.common.util.PageUtil; |
|||
import com.qs.serve.modules.his.service.HisUserChannelPointService; |
|||
import com.qs.serve.modules.oms.entity.OmsOrder; |
|||
import com.qs.serve.task.HisTask; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/4/17 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
@RestController |
|||
@RequestMapping("his/dev") |
|||
@ConditionalOnBean(HisTask.class) |
|||
public class HistTestController { |
|||
|
|||
HisUserChannelPointService hisUserChannelPointService; |
|||
RedisService redisService; |
|||
HisTask hisTask; |
|||
|
|||
@GetMapping("/initSupplier") |
|||
public R<?> initSupplier(){ |
|||
if(DevEnvironmentConfig.isDev()){ |
|||
redisService.set(RedisCacheKeys.HIS_UPDATE,1); |
|||
hisTask.buildTempTable(); |
|||
} |
|||
return R.ok(); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* |
|||
* @return |
|||
*/ |
|||
@GetMapping("/initPoint") |
|||
public R<?> initPoint(){ |
|||
if(DevEnvironmentConfig.isDev()){ |
|||
hisUserChannelPointService.initSetup(); |
|||
} |
|||
return R.ok(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,96 @@ |
|||
package com.qs.serve.task.controller; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.qs.serve.common.model.dto.R; |
|||
import com.qs.serve.common.util.CollectionUtil; |
|||
import com.qs.serve.modules.seeyon.service.impl.SeeYonRequestBaseService; |
|||
import com.qs.serve.modules.tbs.common.TbsActivityState; |
|||
import com.qs.serve.modules.tbs.common.TbsSeeYonConst; |
|||
import com.qs.serve.modules.tbs.entity.TbsActivity; |
|||
import com.qs.serve.modules.tbs.entity.TbsActivityTemplate; |
|||
import com.qs.serve.modules.tbs.service.TbsActivityService; |
|||
import com.qs.serve.modules.tbs.service.TbsActivityTemplateService; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.time.LocalDate; |
|||
import java.time.LocalDateTime; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 【同步】 活动相关 |
|||
* @author YenHex |
|||
* @since 2023/6/27 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/task/activity") |
|||
//@ConditionalOnProperty(value = "project.task", havingValue = "true")
|
|||
public class TaskActivityController { |
|||
|
|||
private final TbsActivityService activityService; |
|||
private final TbsActivityTemplateService activityTemplateService; |
|||
private final SeeYonRequestBaseService seeYonRequestBaseService; |
|||
|
|||
|
|||
|
|||
/** |
|||
* 同步ERP的发货单,用于计算活动费率 |
|||
* @return |
|||
*/ |
|||
@GetMapping("syncDispatch") |
|||
public R task0(){ |
|||
seeYonRequestBaseService.getBase(TbsSeeYonConst.TASK_SYNC_DISPATCH,"同步ERP的发货单"); |
|||
return R.ok(); |
|||
} |
|||
|
|||
/** |
|||
* 每日更新过期的活动,过期则进行冻结 |
|||
* @return |
|||
*/ |
|||
@GetMapping("lockActivity") |
|||
public R task2(){ |
|||
LambdaQueryWrapper<TbsActivity> lqw = new LambdaQueryWrapper<>(); |
|||
lqw.le(TbsActivity::getPreEndDate, LocalDate.now()); |
|||
lqw.eq(TbsActivity::getReopenFlag,0); |
|||
TbsActivity param = new TbsActivity(); |
|||
param.setActivityState(TbsActivityState.STATE_1_Baning); |
|||
activityService.update(param,lqw); |
|||
return R.ok(); |
|||
} |
|||
|
|||
/** |
|||
* 启用和停用模板规则 |
|||
* @return |
|||
*/ |
|||
@GetMapping("startAndStopActivityTemplates") |
|||
public R task3(){ |
|||
LocalDateTime nowTime = LocalDateTime.now(); |
|||
LambdaQueryWrapper<TbsActivityTemplate> lqw = new LambdaQueryWrapper<>(); |
|||
lqw.select(TbsActivityTemplate::getId); |
|||
lqw.ge(TbsActivityTemplate::getStartTime,nowTime.with(LocalDateTime.MIN)); |
|||
lqw.le(TbsActivityTemplate::getStartTime,nowTime.with(LocalDateTime.MAX)); |
|||
lqw.eq(TbsActivityTemplate::getTemplateState,0); |
|||
List<TbsActivityTemplate> preStartList = activityTemplateService.list(lqw); |
|||
if(CollectionUtil.isNotEmpty(preStartList)){ |
|||
preStartList.forEach(a->a.setTemplateState(1)); |
|||
activityTemplateService.updateBatchById(preStartList); |
|||
} |
|||
LambdaQueryWrapper<TbsActivityTemplate> lqw2 = new LambdaQueryWrapper<>(); |
|||
lqw2.select(TbsActivityTemplate::getId); |
|||
lqw2.ge(TbsActivityTemplate::getEndTime,nowTime.with(LocalDateTime.MIN)); |
|||
lqw2.le(TbsActivityTemplate::getEndTime,nowTime.with(LocalDateTime.MAX)); |
|||
lqw2.eq(TbsActivityTemplate::getTemplateState,1); |
|||
List<TbsActivityTemplate> preCloseList = activityTemplateService.list(lqw2); |
|||
if(CollectionUtil.isNotEmpty(preCloseList)){ |
|||
preCloseList.forEach(a->a.setTemplateState(0)); |
|||
activityTemplateService.updateBatchById(preCloseList); |
|||
} |
|||
return R.ok(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,30 @@ |
|||
package com.qs.serve.task.controller; |
|||
|
|||
import com.qs.serve.common.model.dto.R; |
|||
import com.qs.serve.modules.pay.service.impl.PayApplicationService; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/11/2 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/task/pay") |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class TaskPayController { |
|||
|
|||
PayApplicationService applicationService; |
|||
|
|||
@RequestMapping("test") |
|||
public R<?> task(){ |
|||
applicationService.syncTotalPayToActivity(); |
|||
return R.ok(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,45 @@ |
|||
package com.qs.serve.task.controller; |
|||
|
|||
import com.qs.serve.common.model.dto.R; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
/** |
|||
* 【同步】 政策相关 |
|||
* @author YenHex |
|||
* @since 2023/6/27 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/task/policy") |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class TaskPolicyController { |
|||
|
|||
//TzcPolicyTask policyTask;
|
|||
|
|||
/** |
|||
* 根据销路通支付数据,和本系统政策匹对,并生成本系统核销及支付信息 |
|||
* @return |
|||
*/ |
|||
@GetMapping("loadXltPayment") |
|||
public R syncFromXltPolicyPayment(){ |
|||
//policyTask.syncFromXltPolicyPayment();
|
|||
return R.ok(); |
|||
} |
|||
|
|||
/** |
|||
* 同步政策到销路通 |
|||
* @return |
|||
*/ |
|||
@GetMapping("syncPolicyToXlt") |
|||
public R syncPolicyToXlt(){ |
|||
//policyTask.syncPolicyToXlt();
|
|||
return R.ok(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,65 @@ |
|||
package com.qs.serve.task.controller; |
|||
|
|||
import com.qs.serve.common.framework.redis.RedisService; |
|||
import com.qs.serve.common.model.consts.RedisCacheKeys; |
|||
import com.qs.serve.common.model.dto.R; |
|||
import com.qs.serve.modules.his.service.HisUserSupplierTempService; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.time.Duration; |
|||
import java.time.LocalDateTime; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
/** |
|||
* 【同步】 客户相关 |
|||
* @author YenHex |
|||
* @since 2023/6/27 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/task/supplier") |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class TaskSupplierController { |
|||
|
|||
RedisService redisService; |
|||
HisUserSupplierTempService tempService; |
|||
|
|||
/** |
|||
* 通过客户底表 |
|||
* @return |
|||
*/ |
|||
@GetMapping("syncToTemp") |
|||
public R test(){ |
|||
Integer opt = redisService.getInteger(RedisCacheKeys.HIS_UPDATE); |
|||
log.warn("======================执行状态:"+opt+"======================"); |
|||
//设置默认值
|
|||
if (opt==null){ |
|||
redisService.set(RedisCacheKeys.HIS_UPDATE,0); |
|||
return R.ok(); |
|||
} |
|||
//忽略状态
|
|||
if (opt==1){ |
|||
//执行同步
|
|||
log.warn("======================执行同步======================"); |
|||
LocalDateTime s1 = LocalDateTime.now(); |
|||
//防卡死,加入超时
|
|||
redisService.set(RedisCacheKeys.HIS_UPDATE,2,1, TimeUnit.HOURS); |
|||
tempService.reloadHis(); |
|||
LocalDateTime s2 = LocalDateTime.now(); |
|||
long diff = Duration.between(s1, s2).getSeconds(); |
|||
tempService.selectInfoHis(); |
|||
redisService.set(RedisCacheKeys.HIS_UPDATE,0); |
|||
log.warn("======================执行同步完成,耗时[ {} 秒]======================",diff); |
|||
} |
|||
return R.ok(); |
|||
} |
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,106 @@ |
|||
package com.qs.serve.task.controller; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.qs.serve.common.model.dto.R; |
|||
import com.qs.serve.common.util.JsonUtil; |
|||
import com.qs.serve.modules.bms.mapper.BmsSupplierMapper; |
|||
import com.qs.serve.modules.his.service.HisUserSupplierService; |
|||
import com.qs.serve.modules.seeyon.service.impl.SeeYonRequestBaseService; |
|||
import com.qs.serve.modules.sys.entity.SysUser; |
|||
import com.qs.serve.modules.sys.entity.SysUserLeave; |
|||
import com.qs.serve.modules.sys.entity.dto.SyUser; |
|||
import com.qs.serve.modules.sys.service.SysUserLeaveService; |
|||
import com.qs.serve.modules.sys.service.SysUserService; |
|||
import com.qs.serve.modules.tbs.common.TbsSeeYonConst; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.transaction.annotation.Transactional; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.time.LocalDate; |
|||
import java.util.List; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 【同步】 用户相关 |
|||
* @author YenHex |
|||
* @since 2023/6/27 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/task/user") |
|||
//@ConditionalOnProperty(value = "project.task", havingValue = "true")
|
|||
public class TaskUserController { |
|||
|
|||
SeeYonRequestBaseService seeYonRequestBaseService; |
|||
SysUserService sysUserService; |
|||
SysUserLeaveService sysUserLeaveService; |
|||
private final BmsSupplierMapper supplierMapper; |
|||
private final HisUserSupplierService hisUserSupplierService; |
|||
|
|||
@Transactional |
|||
public R<?> doLeave(){ |
|||
LambdaQueryWrapper<SysUserLeave> lqw = new LambdaQueryWrapper<>(); |
|||
lqw.select(SysUserLeave::getUserId,SysUserLeave::getId); |
|||
lqw.le(SysUserLeave::getLeaveEffectDate, LocalDate.now()); |
|||
lqw.eq(SysUserLeave::getLeaveStatus,0); |
|||
List<SysUserLeave> sysUserLeaves = sysUserLeaveService.list(lqw); |
|||
if(sysUserLeaves.size()<1){ |
|||
return null; |
|||
} |
|||
for (SysUserLeave userLeaf : sysUserLeaves) { |
|||
userLeaf.setLeaveStatus(1); |
|||
} |
|||
sysUserLeaveService.updateBatchById(sysUserLeaves); |
|||
List<String> userIds = sysUserLeaves.stream().map(a->a.getUserId()).collect(Collectors.toList()); |
|||
sysUserService.leaveNow(userIds,false); |
|||
return R.ok(); |
|||
} |
|||
|
|||
/** |
|||
* 同步致远的用户到CRM |
|||
* @return |
|||
*/ |
|||
@GetMapping("syncFromSeeYon") |
|||
public R test(){ |
|||
R<String> rs = seeYonRequestBaseService.getBase(TbsSeeYonConst.OA_USER_LIST_1,null); |
|||
String listJson = rs.getData(); |
|||
List<SyUser> userList = JsonUtil.jsonToList(listJson, SyUser.class); |
|||
assert userList != null; |
|||
if(userList.size()<1){ |
|||
return R.ok(); |
|||
} |
|||
List<String> codes = userList.stream().map(SyUser::getCode).collect(Collectors.toList()); |
|||
LambdaQueryWrapper<SysUser> userLqw = new LambdaQueryWrapper<>(); |
|||
userLqw.in(SysUser::getAccount,codes).or() |
|||
.in(SysUser::getCode,codes); |
|||
List<SysUser> existUserList = sysUserService.list(userLqw); |
|||
for (SyUser oaUser : userList) { |
|||
boolean exist = existUserList.stream().anyMatch( |
|||
a->a.getAccount().equals(oaUser.getCode()) |
|||
||a.getCode().equals(oaUser.getCode()) |
|||
); |
|||
if(!exist){ |
|||
SysUser sysUser = new SysUser(); |
|||
sysUser.setCode(oaUser.getCode()); |
|||
sysUser.setMobile(oaUser.getMobile()); |
|||
sysUser.setAccount(oaUser.getCode()); |
|||
sysUser.setId(oaUser.getId()); |
|||
sysUser.setSyUserId(oaUser.getId()); |
|||
sysUser.setSyAccount(oaUser.getCode()); |
|||
sysUser.setServingState(1); |
|||
sysUser.setServingDate(LocalDate.now()); |
|||
sysUser.setSuperFlag(1); |
|||
sysUser.setTenantId("001"); |
|||
sysUserService.save(sysUser); |
|||
} |
|||
} |
|||
return R.ok(); |
|||
} |
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,38 @@ |
|||
package com.qs.serve.task.controller; |
|||
|
|||
import com.qs.serve.common.model.dto.R; |
|||
import com.qs.serve.modules.wx.service.WxUserService; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
/** |
|||
* 【同步】 微信相关 |
|||
* @author YenHex |
|||
* @since 2023/6/27 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/task/wechat") |
|||
@ConditionalOnProperty(value = "project.task", havingValue = "true") |
|||
public class TaskWechatController { |
|||
|
|||
private WxUserService wxUserService; |
|||
|
|||
/** |
|||
* 同步订阅用户流程 |
|||
* @return |
|||
*/ |
|||
@GetMapping("syncSubscribe") |
|||
public R test(){ |
|||
wxUserService.syncSubscribe(); |
|||
return R.ok(); |
|||
} |
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,133 @@ |
|||
feign: |
|||
client: |
|||
config: |
|||
default: |
|||
connectTimeout: 5000 # 连接超时时间 |
|||
readTimeout: 5000 # 读取超时时间 |
|||
httpclient: |
|||
enabled: true |
|||
# 服务列表 |
|||
service-list: |
|||
policy-svc: http://localhost:8081 |
|||
|
|||
#项目配置 |
|||
project: |
|||
bir-service: 'false' |
|||
bir-service-sync: 'false' |
|||
bir-service-url: 'http://192.168.0.9:7401' |
|||
web_url: 'http://192.168.0.9:6031' |
|||
host_url: 'http://192.168.0.9:7400' |
|||
pc-web-local: 'D:\Software\Nginx1.8\html\jslcrm3\' |
|||
apis: |
|||
#支付接口 |
|||
#cost-to-pay: 'http://59.37.164.96:2506/action/cms/api/add' |
|||
#支付接口(新) |
|||
#cost-to-pay: 'http://59.37.164.96:2505/api/cms/api/add' |
|||
cost-to-pay: 'http://0.0.0.0:2505/api/cms/api/add' |
|||
# 同步核销的支付状态 |
|||
#check-pay-status: 'http://59.37.164.96:2506/action/cms/cost/match' |
|||
check-pay-status: 'http://0.0.0.0:2506/action/cms/cost/match' |
|||
# 核销生成报价单接口 |
|||
diaodu-plan-order: '' |
|||
# 嘉士利接口,spu转换sku |
|||
#spu-to-sku: 'http://59.37.164.96:2505/api/cms/order/matchInvCode' |
|||
spu-to-sku: 'http://0.0.0.0:2505/api/cms/order/matchInvCode' |
|||
# 政策同步 |
|||
#policy-sync-cate: 'http://192.168.10.18:9003/api/cms/saleCost/costPolicy/syncCate' |
|||
policy-sync-cate: 'http://0.0.0.0:9003/api/cms/saleCost/costPolicy/syncCate' |
|||
# 政策同步旧的 |
|||
#policy-sync-inv: 'http://192.168.10.18:9003/api/cms/saleCost/costPolicy/syncInv' |
|||
policy-sync-inv: 'http://0.0.0.0:9003/api/cms/saleCost/costPolicy/syncInv' |
|||
|
|||
task: false |
|||
dev: true |
|||
seeyon: |
|||
enable: true |
|||
url: 'http://192.168.0.9:7444' |
|||
#请求致远OA的拓展服务(用于修改密码) |
|||
extApi: 'http://192.168.10.244:9003/' |
|||
|
|||
upload: |
|||
#上传映射地址 |
|||
proxy-url: https://qsjslservice.oss-cn-guangzhou.aliyuncs.com/jsl/ |
|||
#物理存储地址 |
|||
logical-path: D:\\WebMapPath\\ |
|||
#腾讯云配置 |
|||
tencent: |
|||
sms: |
|||
secret-id: AKIDR3A5mVkSaXFUT3TABanPxc2MtkMu45wb |
|||
secret-key: iLkjeKzHwegQ4eE55xX9byXmBLxgwypV |
|||
sdkAppId: 1400174031 |
|||
signName: 柒胜软件 |
|||
templateId: 689207 |
|||
#天翼云配置 |
|||
tianyi: |
|||
sms: |
|||
appid: 'WIgWyCFn4DnHLtjKBIXBVyZbGevFg3J4' |
|||
appKey: 'bjfsZlF01OZPUzyiCLSFOrOOnfsZhYZJ' |
|||
aliyun: |
|||
oss: |
|||
bucket: qsjslservice |
|||
accessKeyId: LTAI5tHvNJT7M9YZJ9BSmURK |
|||
accessKeySecret: OzH0ea3w8fgjrll9P0XTQlqmEg3Cky |
|||
endpoint: oss-cn-guangzhou.aliyuncs.com |
|||
prefix: jsl |
|||
#服务配置 |
|||
server: |
|||
port: 7400 |
|||
servlet: |
|||
context-path: / |
|||
|
|||
|
|||
|
|||
#SpringBoot相关 |
|||
spring: |
|||
datasource: |
|||
# 旧的 |
|||
# driver-class-name: com.mysql.cj.jdbc.Driver |
|||
# url: jdbc:mysql://192.168.0.9:3306/jsl_mall_qs_dev?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true |
|||
# username: kpjsl |
|||
# password: '123456' |
|||
# 新的 |
|||
dynamic: |
|||
primary: crm_db #设置默认的数据源或者数据源组,默认值即为master |
|||
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 |
|||
datasource: |
|||
crm_db: |
|||
driver-class-name: com.mysql.cj.jdbc.Driver |
|||
url: jdbc:mysql://192.168.0.9:3306/jsl_mall_qs_dev?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true |
|||
username: kpjsl |
|||
password: 123456 |
|||
qisheng: |
|||
url: jdbc:sqlserver://192.168.10.11:1433;DatabaseName=JSL_COST_QS_TEST |
|||
username: sa |
|||
password: JSL2282125 |
|||
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver |
|||
#SpringBoot相关 |
|||
hikari: |
|||
#连接池名 |
|||
pool-name: DateHikariCP |
|||
#最小空闲连接数 |
|||
minimum-idle: 10 |
|||
# 空闲连接存活最大时间,默认600000(10分钟) |
|||
idle-timeout: 180000 |
|||
# 连接池最大连接数,默认是10 |
|||
maximum-pool-size: 30 |
|||
# 此属性控制从池返回的连接的默认自动提交行为,默认值:true |
|||
auto-commit: true |
|||
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟 |
|||
max-lifetime: 1800000 |
|||
# 数据库连接超时时间,默认30秒,即30000 |
|||
connection-timeout: 30000 |
|||
connection-test-query: SELECT 1 |
|||
validation-timeout: 1 |
|||
login-timeout: 5 |
|||
|
|||
redis: |
|||
database: 1 |
|||
host: 127.0.0.1 |
|||
port: 6379 |
|||
password: |
|||
#工作流配置 |
|||
flowable: |
|||
database-schema-update: true |
@ -0,0 +1,92 @@ |
|||
#项目配置 |
|||
project: |
|||
#关闭权限 |
|||
close-auth: 'false' |
|||
#true-请求端;false-接收端 |
|||
bir-service: 'false' |
|||
#对应233服务的的cms |
|||
bir-service-url: 'http://59.37.164.96:7400' |
|||
#bir-service-url: 'http://127.0.0.1:7401' |
|||
web_url: 'http://192.168.0.9:6031' |
|||
host_url: 'http://192.168.0.9:7400' |
|||
pc-web-local: 'D:\Software\Nginx1.8\html\jslcrm3\' |
|||
apis: |
|||
#支付接口 |
|||
cost-to-pay: 'http://59.37.164.96:2505/api/cms/api/add' |
|||
check-pay-status: 'http://59.37.164.96:2506/action/cms/cost/match' |
|||
# 核销生成报价单接口 |
|||
diaodu-plan-order: '' |
|||
# 嘉士利接口,spu转换sku |
|||
spu-to-sku: 'http://59.37.164.96:2505/api/cms/order/matchInvCode' |
|||
# 政策同步 |
|||
policy-sync-cate: 'http://59.37.164.96:2505/api/cms/saleCost/costPolicy/syncCate' |
|||
# 政策同步旧的 |
|||
policy-sync-inv: 'http://59.37.164.96:2505/api/cms/saleCost/costPolicy/syncInv' |
|||
task: false |
|||
dev: false |
|||
seeyon: |
|||
enable: true |
|||
url: 'http://192.168.0.9:7444' |
|||
#请求致远OA的拓展服务(用于修改密码) |
|||
extApi: 'http://192.168.10.244:9003/' |
|||
|
|||
upload: |
|||
#上传映射地址 |
|||
proxy-url: https://qsjslservice.oss-cn-guangzhou.aliyuncs.com/jsl/ |
|||
#物理存储地址 |
|||
logical-path: D:\\WebMapPath\\ |
|||
#腾讯云配置 |
|||
tencent: |
|||
sms: |
|||
secret-id: AKIDR3A5mVkSaXFUT3TABanPxc2MtkMu45wb |
|||
secret-key: iLkjeKzHwegQ4eE55xX9byXmBLxgwypV |
|||
sdkAppId: 1400174031 |
|||
signName: 柒胜软件 |
|||
templateId: 689207 |
|||
#天翼云配置 |
|||
tianyi: |
|||
sms: |
|||
appid: 'WIgWyCFn4DnHLtjKBIXBVyZbGevFg3J4' |
|||
appKey: 'bjfsZlF01OZPUzyiCLSFOrOOnfsZhYZJ' |
|||
aliyun: |
|||
oss: |
|||
bucket: qsjslservice |
|||
accessKeyId: LTAI5tHvNJT7M9YZJ9BSmURK |
|||
accessKeySecret: OzH0ea3w8fgjrll9P0XTQlqmEg3Cky |
|||
endpoint: oss-cn-guangzhou.aliyuncs.com |
|||
prefix: jsl |
|||
#服务配置 |
|||
server: |
|||
port: 7401 |
|||
servlet: |
|||
context-path: / |
|||
#SpringBoot相关 |
|||
spring: |
|||
datasource: |
|||
dynamic: |
|||
primary: crm_db #设置默认的数据源或者数据源组,默认值即为master |
|||
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 |
|||
datasource: |
|||
crm_db: |
|||
driver-class-name: com.mysql.cj.jdbc.Driver |
|||
url: jdbc:mysql://183.56.249.148:3306/jsl_cost_base?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true |
|||
username: root |
|||
password: '@Jsl2282125' |
|||
qisheng: |
|||
url: jdbc:sqlserver://192.168.10.11:1433;DatabaseName=JSL_COST_QS |
|||
username: sa |
|||
password: JSL2282125 |
|||
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver |
|||
# erp: |
|||
# username: sa |
|||
# password: 'JSL2282125' |
|||
# url: jdbc:sqlserver://192.168.10.11:1433;DatabaseName=UFDATA_001_2020 |
|||
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver |
|||
redis: |
|||
database: 2 |
|||
host: 127.0.0.1 |
|||
port: 6379 |
|||
password: |
|||
#工作流配置 |
|||
flowable: |
|||
database-schema-update: true |
@ -0,0 +1,87 @@ |
|||
spring: |
|||
servlet: |
|||
multipart: |
|||
max-file-size: 100MB |
|||
max-request-size: 160MB |
|||
profiles: |
|||
active: dev |
|||
main: |
|||
#easypoi启用覆盖 |
|||
allow-bean-definition-overriding: true |
|||
jmx: |
|||
enabled: false |
|||
devtools: |
|||
restart: |
|||
enabled: false |
|||
#项目配置 |
|||
project: |
|||
ignore-url: |
|||
tenants: #忽略租户拦截 |
|||
- /callback |
|||
- /favicon.ico |
|||
- /error |
|||
- /portal/syKeyLogin |
|||
- /bir/roiRate/test |
|||
- /static/* |
|||
- /api/wx/login/getCpSignature |
|||
- /web/* |
|||
permits: #忽略登录 |
|||
- /thirty/** #第三方接口 |
|||
- /portal/flushToken #第三方接口 |
|||
- /common/upload #支持API上传调整 |
|||
- /common/validToken #验证token |
|||
- /sys/attach/listByIds/** |
|||
- /api/** |
|||
- /static/** |
|||
- /web/** |
|||
- /portal/** |
|||
- /favicon.ico |
|||
- /error |
|||
- /callback |
|||
- /bir/roiRate/test |
|||
|
|||
#mybatis plus |
|||
mybatis-plus: |
|||
mapper-locations: classpath:mapper/*/*.xml |
|||
type-aliases-package: com.qs.serve.modules.*.entity.* |
|||
configuration: |
|||
map-underscore-to-camel-case: true |
|||
#log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl |
|||
global-config: |
|||
banner: false |
|||
db-config: |
|||
logic-delete-value: 1 |
|||
logic-not-delete-value: 0 |
|||
select-strategy: not_empty |
|||
logic-delete-field: delFlag |
|||
# 日志配置 |
|||
logging: |
|||
level: |
|||
ROOT: debug |
|||
com.qs.serve: debug |
|||
com.qs.serve.modules.his: debug |
|||
com.qs.serve.modules.sys: debug |
|||
com.qs.serve.modules.tag: info |
|||
org.xnio.nio: info |
|||
org.springframework: info |
|||
com.baomidou: info |
|||
org.mybatis: info |
|||
org.hibernate.validator: info |
|||
druid.sql.ResultSet: info |
|||
druid.sql.Connection: info |
|||
com.zaxxer.hikari.pool: info |
|||
com.zaxxer.hikari.HikariConfig: info |
|||
com.qs.serve.modules.sys.mapper.SysOperationLogMapper: info |
|||
java.io: warn |
|||
io.netty: info |
|||
io.undertow: info |
|||
io.lettuce.core: info |
|||
config: classpath:log4j2.xml |
|||
# PageHelper分页插件 |
|||
pagehelper: |
|||
reasonable: false |
|||
#helper-dialect: sqlserver |
|||
autoRuntimeDialect: true |
|||
supportMethodsArguments: true |
|||
params: count=countSql |
|||
|
@ -0,0 +1,4 @@ |
|||
${AnsiBackground.BLACK} |
|||
-- ---------------------------- |
|||
-- 嘉士利CRM系统 by.柒胜 |
|||
-- ---------------------------- |
@ -0,0 +1,83 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出--> |
|||
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数--> |
|||
<configuration monitorInterval="5"> |
|||
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> |
|||
|
|||
<!--变量配置--> |
|||
<Properties> |
|||
<property name="LOG_PATTERN" value="%d %highlight{%-5level}{ERROR=Bright RED, WARN=Bright Yellow, INFO=Bright Green, DEBUG=Bright Cyan, TRACE=Bright White} %style{[%t]}{bright,magenta} %style{%c{1.}.%M(%L)}{cyan}: %msg%n" /> |
|||
<property name="FILE_PATH" value="home/logs" /> |
|||
</Properties> |
|||
|
|||
<appenders> |
|||
<!-- console --> |
|||
<console name="Console" target="SYSTEM_OUT"> |
|||
<PatternLayout pattern="${LOG_PATTERN}"/> |
|||
<ThresholdFilter level="all" onMatch="ACCEPT" onMismatch="DENY"/> |
|||
</console> |
|||
|
|||
<File name="FileLog" fileName="${FILE_PATH}/test.log" append="false" filePattern="${FILE_PATH}/test-%d{yyyy-MM-dd}_%i.log.gz"> |
|||
<PatternLayout pattern="${LOG_PATTERN}"/> |
|||
<Policies> |
|||
<TimeBasedTriggeringPolicy interval="1"/> |
|||
<SizeBasedTriggeringPolicy size="10MB"/> |
|||
</Policies> |
|||
<DefaultRolloverStrategy max="15"/> |
|||
</File> |
|||
|
|||
<!-- debug --> |
|||
<RollingFile name="RollingFileDebug" fileName="${FILE_PATH}/debug.log" filePattern="${FILE_PATH}/debug-%d{yyyy-MM-dd}_%i.log.gz"> |
|||
<ThresholdFilter level="all" onMatch="ACCEPT" onMismatch="DENY"/> |
|||
<Policies> |
|||
<TimeBasedTriggeringPolicy interval="1"/> |
|||
<SizeBasedTriggeringPolicy size="10MB"/> |
|||
</Policies> |
|||
<DefaultRolloverStrategy max="15"/> |
|||
</RollingFile> |
|||
|
|||
<!-- info --> |
|||
<RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" filePattern="${FILE_PATH}/info-%d{yyyy-MM-dd}_%i.log.gz"> |
|||
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> |
|||
<PatternLayout pattern="${LOG_PATTERN}"/> |
|||
<Policies> |
|||
<TimeBasedTriggeringPolicy interval="1"/> |
|||
<SizeBasedTriggeringPolicy size="10MB"/> |
|||
</Policies> |
|||
<DefaultRolloverStrategy max="15"/> |
|||
</RollingFile> |
|||
<!-- warn --> |
|||
<RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log" filePattern="${FILE_PATH}/warn-%d{yyyy-MM-dd}_%i.log.gz"> |
|||
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/> |
|||
<PatternLayout pattern="${LOG_PATTERN}"/> |
|||
<Policies> |
|||
<TimeBasedTriggeringPolicy interval="1"/> |
|||
<SizeBasedTriggeringPolicy size="10MB"/> |
|||
</Policies> |
|||
<DefaultRolloverStrategy max="15"/> |
|||
</RollingFile> |
|||
<!-- error --> |
|||
<RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log" filePattern="${FILE_PATH}/error-%d{yyyy-MM-dd}_%i.log.gz"> |
|||
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> |
|||
<PatternLayout pattern="${LOG_PATTERN}"/> |
|||
<Policies> |
|||
<TimeBasedTriggeringPolicy interval="1"/> |
|||
<SizeBasedTriggeringPolicy size="10MB"/> |
|||
</Policies> |
|||
<DefaultRolloverStrategy max="15"/> |
|||
</RollingFile> |
|||
|
|||
</appenders> |
|||
|
|||
<loggers> |
|||
<root level="debug"> |
|||
<appender-ref ref="Console"/> |
|||
<appender-ref ref="FileLog"/> |
|||
<appender-ref ref="RollingFileDebug"/> |
|||
<appender-ref ref="RollingFileInfo"/> |
|||
<appender-ref ref="RollingFileWarn"/> |
|||
<appender-ref ref="RollingFileError"/> |
|||
</root> |
|||
</loggers> |
|||
|
|||
</configuration> |
@ -0,0 +1,80 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出--> |
|||
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数--> |
|||
<configuration monitorInterval="5"> |
|||
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> |
|||
|
|||
<!--变量配置--> |
|||
<Properties> |
|||
<property name="LOG_PATTERN" value="%d %highlight{%-5level}{ERROR=Bright RED, WARN=Bright Yellow, INFO=Bright Green, DEBUG=Bright Cyan, TRACE=Bright White} %style{[%t]}{bright,magenta} %style{%c{1.}.%M(%L)}{cyan}: %msg%n" /> |
|||
<!--<property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />--> |
|||
<property name="FILE_PATH" value="logs" /> |
|||
<property name="FILE_NAME" value="api" /> |
|||
</Properties> |
|||
|
|||
<appenders> |
|||
<!-- console --> |
|||
<console name="Console" target="SYSTEM_OUT"> |
|||
<PatternLayout pattern="${LOG_PATTERN}"/> |
|||
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/> |
|||
</console> |
|||
<File name="Filelog" fileName="${FILE_PATH}/test.log" append="false"> |
|||
<PatternLayout pattern="${LOG_PATTERN}"/> |
|||
<Policies> |
|||
<TimeBasedTriggeringPolicy interval="1"/> |
|||
<SizeBasedTriggeringPolicy size="20MB"/> |
|||
</Policies> |
|||
<DefaultRolloverStrategy max="15"/> |
|||
</File> |
|||
|
|||
<!-- info --> |
|||
<RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz"> |
|||
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> |
|||
<PatternLayout pattern="${LOG_PATTERN}"/> |
|||
<Policies> |
|||
<TimeBasedTriggeringPolicy interval="1"/> |
|||
<SizeBasedTriggeringPolicy size="10MB"/> |
|||
</Policies> |
|||
<DefaultRolloverStrategy max="15"/> |
|||
</RollingFile> |
|||
|
|||
<!-- warn --> |
|||
<RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log" filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz"> |
|||
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/> |
|||
<PatternLayout pattern="${LOG_PATTERN}"/> |
|||
<Policies> |
|||
<TimeBasedTriggeringPolicy interval="1"/> |
|||
<SizeBasedTriggeringPolicy size="10MB"/> |
|||
</Policies> |
|||
<DefaultRolloverStrategy max="15"/> |
|||
</RollingFile> |
|||
<!-- error --> |
|||
<RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz"> |
|||
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> |
|||
<PatternLayout pattern="${LOG_PATTERN}"/> |
|||
<Policies> |
|||
<TimeBasedTriggeringPolicy interval="1"/> |
|||
<SizeBasedTriggeringPolicy size="10MB"/> |
|||
</Policies> |
|||
<DefaultRolloverStrategy max="15"/> |
|||
</RollingFile> |
|||
</appenders> |
|||
|
|||
<loggers> |
|||
<logger name="org.mybatis" level="info" additivity="false"> |
|||
<AppenderRef ref="Console"/> |
|||
</logger> |
|||
<Logger name="org.springframework" level="info" additivity="false"> |
|||
<AppenderRef ref="Console"/> |
|||
</Logger> |
|||
|
|||
<root level="info"> |
|||
<appender-ref ref="Console"/> |
|||
<appender-ref ref="Filelog"/> |
|||
<appender-ref ref="RollingFileInfo"/> |
|||
<appender-ref ref="RollingFileWarn"/> |
|||
<appender-ref ref="RollingFileError"/> |
|||
</root> |
|||
</loggers> |
|||
|
|||
</configuration> |
@ -0,0 +1,19 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<artifactId>cms-api</artifactId> |
|||
<groupId>com.qs</groupId> |
|||
<version>1.0-SNAPSHOT</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<artifactId>cms-policy-svc</artifactId> |
|||
|
|||
<properties> |
|||
<maven.compiler.source>8</maven.compiler.source> |
|||
<maven.compiler.target>8</maven.compiler.target> |
|||
</properties> |
|||
|
|||
</project> |
@ -0,0 +1,27 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<artifactId>jsl-cms</artifactId> |
|||
<groupId>com.qs</groupId> |
|||
<version>1.0-SNAPSHOT</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<packaging>pom</packaging> |
|||
<modules> |
|||
<module>cms-admin-svc</module> |
|||
<module>cms-policy-svc</module> |
|||
</modules> |
|||
<artifactId>cms-api</artifactId> |
|||
|
|||
<properties> |
|||
<maven.compiler.source>8</maven.compiler.source> |
|||
<maven.compiler.target>8</maven.compiler.target> |
|||
</properties> |
|||
|
|||
|
|||
|
|||
|
|||
</project> |
@ -0,0 +1,46 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<artifactId>jsl-cms</artifactId> |
|||
<groupId>com.qs</groupId> |
|||
<version>1.0-SNAPSHOT</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<artifactId>cms-common</artifactId> |
|||
|
|||
<properties> |
|||
<maven.compiler.source>8</maven.compiler.source> |
|||
<maven.compiler.target>8</maven.compiler.target> |
|||
</properties> |
|||
|
|||
<dependencies> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.cloud</groupId> |
|||
<artifactId>spring-cloud-starter-openfeign</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.projectlombok</groupId> |
|||
<artifactId>lombok</artifactId> |
|||
<version>1.18.12</version> |
|||
<scope>compile</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.fasterxml.jackson.datatype</groupId> |
|||
<artifactId>jackson-datatype-jsr310</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.baomidou</groupId> |
|||
<artifactId>mybatis-plus-boot-starter</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-validation</artifactId> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
</project> |
@ -0,0 +1,8 @@ |
|||
package com.qs.serve.common; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2025/4/14 |
|||
*/ |
|||
public class TestCommon { |
|||
} |
@ -0,0 +1,199 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<artifactId>jsl-cms</artifactId> |
|||
<groupId>com.qs</groupId> |
|||
<version>1.0-SNAPSHOT</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<packaging>jar</packaging> |
|||
<artifactId>cms-framework</artifactId> |
|||
|
|||
<properties> |
|||
<maven.compiler.source>8</maven.compiler.source> |
|||
<maven.compiler.target>8</maven.compiler.target> |
|||
</properties> |
|||
|
|||
<dependencies> |
|||
|
|||
<dependency> |
|||
<groupId>com.qs</groupId> |
|||
<artifactId>cms-common</artifactId> |
|||
<version>1.0-SNAPSHOT</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter</artifactId> |
|||
<exclusions> |
|||
<exclusion> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-logging</artifactId> |
|||
</exclusion> |
|||
</exclusions> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-web</artifactId> |
|||
<exclusions> |
|||
<exclusion> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-tomcat</artifactId> |
|||
</exclusion> |
|||
</exclusions> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-undertow</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-data-redis</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-security</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-aop</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-validation</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-log4j2</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.squareup.okhttp3</groupId> |
|||
<artifactId>okhttp</artifactId> |
|||
<version>4.10.0</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>easyexcel</artifactId> |
|||
<version>3.3.2</version> |
|||
</dependency> |
|||
|
|||
|
|||
<dependency> |
|||
<groupId>cn.hutool</groupId> |
|||
<artifactId>hutool-all</artifactId> |
|||
<version>${hutool.version}</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.auth0</groupId> |
|||
<artifactId>java-jwt</artifactId> |
|||
<version>${jwt.version}</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>fastjson</artifactId> |
|||
</dependency> |
|||
|
|||
|
|||
<dependency> |
|||
<groupId>com.github.pagehelper</groupId> |
|||
<artifactId>pagehelper-spring-boot-starter</artifactId> |
|||
<version>1.4.4</version> |
|||
<exclusions> |
|||
<exclusion> |
|||
<groupId>org.mybatis</groupId> |
|||
<artifactId>mybatis-spring</artifactId> |
|||
</exclusion> |
|||
<exclusion> |
|||
<groupId>org.mybatis</groupId> |
|||
<artifactId>mybatis</artifactId> |
|||
</exclusion> |
|||
</exclusions> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.baomidou</groupId> |
|||
<artifactId>dynamic-datasource-spring-boot-starter</artifactId> |
|||
<version>${mybatis-plus.version}</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.baomidou</groupId> |
|||
<artifactId>mybatis-plus-boot-starter</artifactId> |
|||
<version>${mybatis-plus.version}</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>mysql</groupId> |
|||
<artifactId>mysql-connector-java</artifactId> |
|||
<version>8.0.15</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.microsoft.sqlserver</groupId> |
|||
<artifactId>mssql-jdbc</artifactId> |
|||
<version>8.4.1.jre8</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.apache.commons</groupId> |
|||
<artifactId>commons-lang3</artifactId> |
|||
<version>3.12.0</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.github.binarywang</groupId> |
|||
<artifactId>weixin-java-mp</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.github.binarywang</groupId> |
|||
<artifactId>weixin-java-cp</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-test</artifactId> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.tencentcloudapi</groupId> |
|||
<artifactId>tencentcloud-sdk-java</artifactId> |
|||
<version>3.1.598</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.github.shalousun</groupId> |
|||
<artifactId>smart-doc</artifactId> |
|||
<version>2.4.0</version> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.aliyun.oss</groupId> |
|||
<artifactId>aliyun-sdk-oss</artifactId> |
|||
<version>3.16.1</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>joda-time</groupId> |
|||
<artifactId>joda-time</artifactId> |
|||
<version>2.10</version> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
|
|||
</project> |
@ -0,0 +1,24 @@ |
|||
package com.qs.serve.common.config; |
|||
|
|||
import org.springframework.boot.web.servlet.ServletContextInitializer; |
|||
import org.springframework.context.annotation.Configuration; |
|||
|
|||
import javax.servlet.ServletContext; |
|||
import javax.servlet.ServletException; |
|||
import javax.servlet.SessionTrackingMode; |
|||
import java.util.Collections; |
|||
|
|||
|
|||
/** |
|||
* 禁用jsessionid |
|||
* @author YenHex |
|||
* @since 2022/3/11 |
|||
*/ |
|||
@Configuration |
|||
public class CustomServletContextInitializer implements ServletContextInitializer { |
|||
|
|||
@Override |
|||
public void onStartup(ServletContext servletContext) throws ServletException { |
|||
servletContext.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.COOKIE)); |
|||
} |
|||
} |
@ -0,0 +1,33 @@ |
|||
package com.qs.serve.common.config; |
|||
|
|||
import com.qs.serve.common.util.Assert; |
|||
import lombok.experimental.UtilityClass; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/3/11 |
|||
*/ |
|||
@Slf4j |
|||
@UtilityClass |
|||
public class DevEnvironmentConfig { |
|||
|
|||
private static Boolean devEnv = null; |
|||
public static void openDevEnv(Boolean open){ |
|||
log.warn("环境变量:devEnv=>>> "+open); |
|||
devEnv = open; |
|||
} |
|||
|
|||
public static Boolean isDev(){ |
|||
if(devEnv==null){ |
|||
Assert.throwEx("资源加载中..."); |
|||
} |
|||
return devEnv; |
|||
} |
|||
|
|||
/** |
|||
* 开启账套 |
|||
*/ |
|||
public final static boolean OPEN_TENANT_BOOK = true; |
|||
|
|||
} |
@ -0,0 +1,23 @@ |
|||
package com.qs.serve.common.config; |
|||
|
|||
|
|||
import lombok.Getter; |
|||
|
|||
/** |
|||
* @Author: YenHex |
|||
* @Date: 2021/3/3 |
|||
* @Version: 1.0 |
|||
**/ |
|||
@Getter |
|||
public class JwtConfig { |
|||
|
|||
/** |
|||
* 单位分钟 |
|||
*/ |
|||
private final Integer expire = 7; |
|||
|
|||
private final String iss = "KP_ISS"; |
|||
|
|||
private final String secret = "QiShenAa18n9VUcCxaSeSqLtFvsSCaRoVPKtBLaYxB0123456"; |
|||
|
|||
} |
@ -0,0 +1,83 @@ |
|||
package com.qs.serve.common.config; |
|||
|
|||
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
|||
import org.springframework.cache.CacheManager; |
|||
import org.springframework.cache.annotation.CachingConfigurerSupport; |
|||
import org.springframework.cache.annotation.EnableCaching; |
|||
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.core.RedisTemplate; |
|||
import org.springframework.data.redis.listener.RedisMessageListenerContainer; |
|||
import org.springframework.data.redis.serializer.*; |
|||
import org.springframework.data.redis.serializer.RedisSerializationContext; |
|||
import org.springframework.data.redis.serializer.StringRedisSerializer; |
|||
|
|||
import java.time.Duration; |
|||
|
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/2/24 |
|||
*/ |
|||
@EnableCaching |
|||
@Configuration(proxyBeanMethods = false) |
|||
public class RedisConfig extends CachingConfigurerSupport{ |
|||
|
|||
private static final StringRedisSerializer STRING_SERIALIZER = new StringRedisSerializer(); |
|||
private static final GenericJackson2JsonRedisSerializer JACKSON__SERIALIZER = new GenericJackson2JsonRedisSerializer(); |
|||
|
|||
@Bean |
|||
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { |
|||
//设置缓存过期时间
|
|||
RedisCacheConfiguration redisCacheCfg=RedisCacheConfiguration.defaultCacheConfig() |
|||
.entryTtl(Duration.ofHours(1)) |
|||
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(STRING_SERIALIZER)) |
|||
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(JACKSON__SERIALIZER)); |
|||
return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)) |
|||
.cacheDefaults(redisCacheCfg) |
|||
.build(); |
|||
} |
|||
|
|||
// @Bean
|
|||
// public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
|
|||
// JavaTimeModule module = new JavaTimeModule();
|
|||
// DateTimeFormatter formatter = new DateTimeFormatterBuilder()
|
|||
// .appendPattern("yyyy-MM-dd HH:mm:ss").toFormatter();
|
|||
// module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter));
|
|||
// module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));
|
|||
// ObjectMapper objectMapper = builder.createXmlMapper(false).build();
|
|||
// objectMapper.registerModule(new JavaTimeModule());
|
|||
// objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
|||
// return objectMapper;
|
|||
// }
|
|||
|
|||
@Bean |
|||
public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory){ |
|||
RedisMessageListenerContainer container = new RedisMessageListenerContainer(); |
|||
container.setConnectionFactory(connectionFactory); |
|||
return container; |
|||
} |
|||
|
|||
@Bean |
|||
@ConditionalOnMissingBean(name = "redisTemplate") |
|||
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){ |
|||
// 配置redisTemplate
|
|||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); |
|||
redisTemplate.setConnectionFactory(factory); |
|||
// key序列化
|
|||
redisTemplate.setKeySerializer(STRING_SERIALIZER); |
|||
// value序列化
|
|||
redisTemplate.setValueSerializer(JACKSON__SERIALIZER); |
|||
// Hash key序列化
|
|||
redisTemplate.setHashKeySerializer(STRING_SERIALIZER); |
|||
// Hash value序列化
|
|||
redisTemplate.setHashValueSerializer(JACKSON__SERIALIZER); |
|||
redisTemplate.afterPropertiesSet(); |
|||
return redisTemplate; |
|||
} |
|||
} |
@ -0,0 +1,72 @@ |
|||
package com.qs.serve.common.config; |
|||
|
|||
import com.qs.serve.common.config.properties.ProjectProperties; |
|||
import com.qs.serve.common.framework.interceptor.LimitSubmitInterceptor; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.web.cors.CorsConfiguration; |
|||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
|||
import org.springframework.web.filter.CorsFilter; |
|||
import org.springframework.web.multipart.MultipartResolver; |
|||
import org.springframework.web.multipart.commons.CommonsMultipartResolver; |
|||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; |
|||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; |
|||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/2/24 |
|||
*/ |
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
@Configuration(proxyBeanMethods = false) |
|||
public class SpringMvcConfig implements WebMvcConfigurer { |
|||
|
|||
private final LimitSubmitInterceptor limitSubmitInterceptor; |
|||
//private final ApiAuthInterceptor apiAuthInterceptor;
|
|||
|
|||
private final ProjectProperties projectProperties; |
|||
|
|||
@Override |
|||
public void addInterceptors(InterceptorRegistry registry) { |
|||
registry.addInterceptor(limitSubmitInterceptor) |
|||
.addPathPatterns("/**"); |
|||
} |
|||
|
|||
@Override |
|||
public void addResourceHandlers(ResourceHandlerRegistry registry) { |
|||
log.warn("PcWebLocal==>{}",projectProperties.getPcWebLocal()); |
|||
registry.addResourceHandler("/web/**") |
|||
.addResourceLocations("file:"+projectProperties.getPcWebLocal()); |
|||
registry.addResourceHandler("/static/**") |
|||
.addResourceLocations("file:"+projectProperties.getPcWebLocal()+"static/"); |
|||
} |
|||
|
|||
@Bean |
|||
public CorsFilter corsFilter() { |
|||
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); |
|||
final CorsConfiguration corsConfiguration = new CorsConfiguration(); |
|||
/*是否允许请求带有验证信息*/ |
|||
corsConfiguration.setAllowCredentials(true); |
|||
/*允许访问的客户端域名*/ |
|||
corsConfiguration.addAllowedOrigin("*"); |
|||
/*允许服务端访问的客户端请求头*/ |
|||
corsConfiguration.addAllowedHeader("*"); |
|||
/*允许访问的方法名,GET POST等*/ |
|||
corsConfiguration.addAllowedMethod("*"); |
|||
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration); |
|||
return new CorsFilter(urlBasedCorsConfigurationSource); |
|||
} |
|||
|
|||
//@Bean
|
|||
public MultipartResolver multipartResolver(){ |
|||
CommonsMultipartResolver resolver = new CommonsMultipartResolver(); |
|||
resolver.setMaxInMemorySize(5120); |
|||
resolver.setMaxInMemorySize(300 * 1024 * 1024); |
|||
resolver.setDefaultEncoding("UTF-8"); |
|||
return resolver; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,56 @@ |
|||
package com.qs.serve.common.config; |
|||
|
|||
import com.qs.serve.common.util.ThreadsUtils; |
|||
import org.apache.commons.lang3.concurrent.BasicThreadFactory; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
|||
|
|||
import java.util.concurrent.ScheduledExecutorService; |
|||
import java.util.concurrent.ScheduledThreadPoolExecutor; |
|||
import java.util.concurrent.ThreadPoolExecutor; |
|||
|
|||
|
|||
/** |
|||
* 线程池配置 |
|||
* @author YenHex |
|||
* @since 2022/2/24 |
|||
*/ |
|||
@Configuration |
|||
public class ThreadPoolConfig { |
|||
|
|||
/** 核心线程池大小 */ |
|||
private final int corePoolSize = 50; |
|||
|
|||
|
|||
@Bean(name = "threadPoolTaskExecutor") |
|||
public ThreadPoolTaskExecutor threadPoolTaskExecutor() { |
|||
// 最大可创建的线程数
|
|||
int maxPoolSize = 200; |
|||
// 队列最大长度
|
|||
int queueCapacity = 1000; |
|||
// 线程池维护线程所允许的空闲时间
|
|||
int keepAliveSeconds = 300; |
|||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); |
|||
executor.setMaxPoolSize(maxPoolSize); |
|||
executor.setCorePoolSize(corePoolSize); |
|||
executor.setQueueCapacity(queueCapacity); |
|||
executor.setKeepAliveSeconds(keepAliveSeconds); |
|||
// 线程池对拒绝任务(无线程可用)的处理策略
|
|||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); |
|||
return executor; |
|||
} |
|||
|
|||
/** 执行周期性或定时任务 */ |
|||
@Bean(name = "scheduledExecutorService") |
|||
protected ScheduledExecutorService scheduledExecutorService() { |
|||
return new ScheduledThreadPoolExecutor(corePoolSize, |
|||
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) { |
|||
@Override |
|||
protected void afterExecute(Runnable r, Throwable t) { |
|||
super.afterExecute(r, t); |
|||
ThreadsUtils.printException(r, t); |
|||
} |
|||
}; |
|||
} |
|||
} |
@ -0,0 +1,25 @@ |
|||
package com.qs.serve.common.config.properties; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @Author: YenHex |
|||
* @Date: 2021/3/3 |
|||
* @Version: 1.0 |
|||
**/ |
|||
@Getter |
|||
@Setter |
|||
@Component |
|||
@ConfigurationProperties(prefix = "aliyun.oss") |
|||
public class AliYunOssProperties { |
|||
|
|||
private String bucket; |
|||
private String accessKeyId; |
|||
private String accessKeySecret; |
|||
private String endpoint; |
|||
private String prefix; |
|||
|
|||
} |
@ -0,0 +1,13 @@ |
|||
package com.qs.serve.common.config.properties; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2024/3/27 |
|||
*/ |
|||
public class AuthUrlConst { |
|||
|
|||
public final static String[] AUTH_ALLOW_URL = new String[]{ |
|||
"bir/" |
|||
}; |
|||
|
|||
} |
@ -0,0 +1,32 @@ |
|||
package com.qs.serve.common.config.properties; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @Author: YenHex |
|||
* @Date: 2021/3/3 |
|||
* @Version: 1.0 |
|||
**/ |
|||
@Getter |
|||
@Setter |
|||
@Component |
|||
@ConfigurationProperties(prefix = "project.ignore-url") |
|||
public class PermitProperties { |
|||
|
|||
/** |
|||
* 可通过路径(适用于回调场景、无拦截场景等) |
|||
*/ |
|||
private List<String> permits = new ArrayList<>(); |
|||
|
|||
/** |
|||
* 默认租户拦截(适用于无需登录接口,但有租户拦截) |
|||
*/ |
|||
private List<String> tenants = new ArrayList<>(); |
|||
|
|||
} |
@ -0,0 +1,36 @@ |
|||
package com.qs.serve.common.config.properties; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/9/7 |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
@Component |
|||
@ConfigurationProperties(prefix = "project.apis") |
|||
public class ProjectApisProperties { |
|||
|
|||
/** 支付接口 */ |
|||
private String costToPay; |
|||
|
|||
/** 同步核销的支付状态 */ |
|||
private String checkPayStatus; |
|||
|
|||
/** 调度系统-发货单 */ |
|||
private String diaoduPlanOrder; |
|||
|
|||
/** 嘉士利接口,spu转换sku */ |
|||
private String spuToSku; |
|||
|
|||
/** |
|||
* 原是生成销路通apt的中间表,替换伟成的接口直接生成 |
|||
*/ |
|||
private String policySyncCate; |
|||
|
|||
private String policySyncInv; |
|||
} |
@ -0,0 +1,31 @@ |
|||
package com.qs.serve.common.config.properties; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @Author: YenHex |
|||
* @Date: 2021/3/3 |
|||
* @Version: 1.0 |
|||
**/ |
|||
@Getter |
|||
@Setter |
|||
@Component |
|||
@ConfigurationProperties(prefix = "project") |
|||
public class ProjectProperties { |
|||
|
|||
private String closeAuth; |
|||
|
|||
private String birService; |
|||
|
|||
private String birServiceUrl; |
|||
|
|||
private String hostUrl; |
|||
|
|||
private String webUrl; |
|||
|
|||
private String pcWebLocal; |
|||
|
|||
} |
@ -0,0 +1,22 @@ |
|||
package com.qs.serve.common.config.properties; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2024/6/18 |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
@Component |
|||
@ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.qisheng") |
|||
public class QiShengDsProperties { |
|||
|
|||
private String url; |
|||
private String username; |
|||
private String password; |
|||
|
|||
} |
@ -0,0 +1,25 @@ |
|||
package com.qs.serve.common.config.properties; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/3/7 |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
@Component |
|||
@ConfigurationProperties(prefix = "spring.redis") |
|||
public class RedisProperties { |
|||
|
|||
private String host; |
|||
|
|||
private Integer port; |
|||
|
|||
private String password; |
|||
|
|||
private Integer database; |
|||
} |
@ -0,0 +1,25 @@ |
|||
package com.qs.serve.common.config.properties; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @Author: YenHex |
|||
* @Date: 2021/3/3 |
|||
* @Version: 1.0 |
|||
**/ |
|||
@Getter |
|||
@Setter |
|||
@Component |
|||
@ConfigurationProperties(prefix = "project.seeyon") |
|||
public class SeeYonProperties { |
|||
|
|||
private Boolean enable; |
|||
|
|||
private String url; |
|||
|
|||
private String extApi; |
|||
|
|||
} |
@ -0,0 +1,24 @@ |
|||
package com.qs.serve.common.config.properties; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/3/14 |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
@Component |
|||
@ConfigurationProperties(prefix = "project.upload") |
|||
public class UploadProperties { |
|||
|
|||
private String tempPath; |
|||
|
|||
private String proxyUrl; |
|||
|
|||
private String logicalPath; |
|||
|
|||
} |
@ -0,0 +1,35 @@ |
|||
package com.qs.serve.common.framework.annotations; |
|||
|
|||
import java.lang.annotation.*; |
|||
|
|||
/** |
|||
* 解决原有@CacheAble不支持独立失效策略场景 |
|||
* @author YenHex |
|||
* @since 2024/10/17 |
|||
*/ |
|||
@Target({ElementType.METHOD}) |
|||
@Retention(RetentionPolicy.RUNTIME) |
|||
@Documented |
|||
public @interface RedisCacheable { |
|||
|
|||
/** |
|||
* redis缓存前缀,默认类与方法名 |
|||
* @return |
|||
*/ |
|||
String prefix() default ""; |
|||
|
|||
/** |
|||
* 过期时间 |
|||
* @return |
|||
*/ |
|||
int expire() default 350; |
|||
|
|||
/** |
|||
* 缓存读取主键表达式 |
|||
* @return |
|||
*/ |
|||
String expression() default ""; |
|||
|
|||
String SIMPLE_KEY = "#key"; |
|||
|
|||
} |
@ -0,0 +1,4 @@ |
|||
package com.qs.serve.common.framework.annotations; |
|||
|
|||
public @interface TagField { |
|||
} |
@ -0,0 +1,133 @@ |
|||
package com.qs.serve.common.framework.aop; |
|||
|
|||
import com.baomidou.mybatisplus.core.toolkit.StringPool; |
|||
import com.qs.serve.common.framework.annotations.RedisCacheable; |
|||
import com.qs.serve.common.framework.redis.RedisService; |
|||
import com.qs.serve.common.util.JsonUtil; |
|||
import com.qs.serve.common.util.StringUtils; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.aspectj.lang.ProceedingJoinPoint; |
|||
import org.aspectj.lang.Signature; |
|||
import org.aspectj.lang.annotation.Around; |
|||
import org.aspectj.lang.annotation.Pointcut; |
|||
import org.aspectj.lang.reflect.MethodSignature; |
|||
import org.springframework.core.annotation.AnnotatedElementUtils; |
|||
|
|||
import java.lang.reflect.Method; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2024/10/18 |
|||
*/ |
|||
@Slf4j |
|||
//@Aspect
|
|||
//@Component
|
|||
@AllArgsConstructor |
|||
public class RedisCacheAspect { |
|||
|
|||
private final RedisService redisService; |
|||
|
|||
@Pointcut("@annotation(com.qs.serve.common.framework.annotations.RedisCacheable)") |
|||
public void PointCut() {} |
|||
|
|||
@Around("PointCut()") |
|||
public Object redisCacheAdvice(ProceedingJoinPoint joinPoint) throws Throwable { |
|||
Object[] args = joinPoint.getArgs(); |
|||
Signature signature = joinPoint.getSignature(); |
|||
MethodSignature methodSignature = ((MethodSignature) signature); |
|||
Method method = methodSignature.getMethod(); |
|||
RedisCacheable redisCacheable = AnnotatedElementUtils.findMergedAnnotation(method, RedisCacheable.class); |
|||
if(redisCacheable!=null){ |
|||
String prefix = StringUtils.hasText(redisCacheable.prefix()) ? redisCacheable.prefix() |
|||
: methodSignature.getDeclaringType().getName() +"."+ methodSignature.getMethod().getName()+"()"; |
|||
//构建表达式key
|
|||
String pk = this.getPrimaryKey(methodSignature,redisCacheable,args); |
|||
String redisCacheKey = "RCache:" + prefix + (pk==null?"":pk); |
|||
Object result = redisService.get(redisCacheKey); |
|||
if(result!=null){ |
|||
return JsonUtil.jsonToMap(result.toString()); |
|||
} |
|||
result = joinPoint.proceed(args); |
|||
if(result!=null){ |
|||
redisService.set(redisCacheKey,JsonUtil.objectToJson(result),redisCacheable.expire(), TimeUnit.MILLISECONDS); |
|||
} |
|||
return result; |
|||
} |
|||
// 返回默认对象
|
|||
return joinPoint.proceed(args); |
|||
} |
|||
|
|||
public String getPrimaryKey(MethodSignature methodSignature,RedisCacheable annotation,Object[] args){ |
|||
String method = methodSignature.getDeclaringType().getName() |
|||
+"."+ methodSignature.getMethod().getName()+"()"; |
|||
final String expression = annotation.expression(); |
|||
//适配表达式读取key,key读取不到log.error,放行请求
|
|||
String primaryKey = null; |
|||
if(StringUtils.isNotEmpty(expression)){ |
|||
//
|
|||
if(expression.equals(RedisCacheable.SIMPLE_KEY)&&args.length==1){ |
|||
return args[0].toString(); |
|||
} |
|||
List<String> keys = new ArrayList<>(); |
|||
// 指定表名
|
|||
String tableName = null; |
|||
if(expression.contains(StringPool.DOT)){ |
|||
String[] keyArr = expression.split(StringPool.BACK_SLASH + StringPool.DOT); |
|||
for (String key : keyArr) { |
|||
if(key.contains(StringPool.DOLLAR)){ |
|||
tableName = key.replace(StringPool.DOLLAR,""); |
|||
continue; |
|||
} |
|||
keys.add(key); |
|||
} |
|||
}else { |
|||
keys.add(expression); |
|||
} |
|||
for (Object arg : args) { |
|||
// 跳过非指定的表名
|
|||
if(tableName!=null){ |
|||
String clazzName = arg.getClass().getSimpleName(); |
|||
if(!clazzName.equals(tableName)){ |
|||
continue; |
|||
} |
|||
} |
|||
// 读取key
|
|||
primaryKey = getPrimaryKeyRecursion(keys, arg, 0); |
|||
} |
|||
if(primaryKey==null){ |
|||
log.error("LockSubmitAspect失效,方法:{} 无法读取主键:{}",method,expression); |
|||
} |
|||
} |
|||
return primaryKey; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 递归读取主键 |
|||
* @param keys |
|||
* @param arg |
|||
* @param startIndex |
|||
* @return |
|||
*/ |
|||
private String getPrimaryKeyRecursion(List<String> keys, Object arg, int startIndex) { |
|||
String key = keys.get(startIndex); |
|||
Map<String,Object> param = JsonUtil.jsonToMap(JsonUtil.objectToJson(arg)); |
|||
Object val = param.get(key); |
|||
if(val!=null){ |
|||
boolean isLast = startIndex + 1== keys.size(); |
|||
if(isLast){ |
|||
return val.toString(); |
|||
}else { |
|||
// 自调支持无限层级
|
|||
return getPrimaryKeyRecursion(keys, val, startIndex + 1 ); |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,21 @@ |
|||
package com.qs.serve.common.framework.exception; |
|||
|
|||
/** |
|||
* @author JcYen |
|||
* @date 2020/6/11 |
|||
* @version 1.0 |
|||
*/ |
|||
public abstract class BaseException extends RuntimeException { |
|||
|
|||
public BaseException(String message){ |
|||
super(message); |
|||
} |
|||
|
|||
/** |
|||
* 错误代码 |
|||
* @return |
|||
*/ |
|||
public abstract int getCode(); |
|||
|
|||
|
|||
} |
@ -0,0 +1,25 @@ |
|||
package com.qs.serve.common.framework.exception; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* @author JcYen |
|||
* @Date 2020/6/11 |
|||
* @Version 1.0 |
|||
*/ |
|||
public class BusinessException extends BaseException implements Serializable { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
private Integer status; |
|||
|
|||
public BusinessException(String message,Integer status) { |
|||
super(message); |
|||
this.status = status; |
|||
} |
|||
|
|||
@Override |
|||
public int getCode() { |
|||
return status; |
|||
} |
|||
} |
@ -0,0 +1,153 @@ |
|||
package com.qs.serve.common.framework.exception; |
|||
|
|||
import com.qs.serve.common.config.DevEnvironmentConfig; |
|||
import com.qs.serve.common.model.dto.R; |
|||
import com.qs.serve.common.model.enums.HttpCode; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.dao.DuplicateKeyException; |
|||
import org.springframework.http.converter.HttpMessageNotReadableException; |
|||
import org.springframework.http.converter.HttpMessageNotWritableException; |
|||
import org.springframework.security.access.AccessDeniedException; |
|||
import org.springframework.security.authentication.BadCredentialsException; |
|||
import org.springframework.security.core.userdetails.UsernameNotFoundException; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.validation.BindException; |
|||
import org.springframework.web.HttpRequestMethodNotSupportedException; |
|||
import org.springframework.web.bind.MethodArgumentNotValidException; |
|||
import org.springframework.web.bind.annotation.ControllerAdvice; |
|||
import org.springframework.web.bind.annotation.ExceptionHandler; |
|||
import org.springframework.web.bind.annotation.ResponseBody; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
import java.sql.SQLIntegrityConstraintViolationException; |
|||
|
|||
|
|||
/** |
|||
* @Author JcYen |
|||
* @Date 2019/6/7 |
|||
* @Version 1.0 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
@ControllerAdvice |
|||
public class UnifiedExceptionHandler { |
|||
|
|||
|
|||
@ExceptionHandler(value = BusinessException.class) |
|||
@ResponseBody |
|||
public R handleBindException(BusinessException e,HttpServletRequest request) { |
|||
log.warn("自定义异常触发【{},{}】,请求地址:{}",e.getCode(),e.getMessage(),request.getRequestURI()); |
|||
return new R(e.getCode(),e.getMessage()); |
|||
} |
|||
|
|||
@ExceptionHandler(value = NullPointerException.class) |
|||
@ResponseBody |
|||
public R handleBindException(NullPointerException e,HttpServletRequest request) { |
|||
StringBuilder stringBuilder = new StringBuilder(); |
|||
for (StackTraceElement element : e.getStackTrace()) { |
|||
if (element.getClassName().contains("qs")){ |
|||
stringBuilder.append(element.getClassName()+":"+element.getLineNumber()+"\n"); |
|||
} |
|||
} |
|||
log.error("\n空指针:{} \n{}",request.getRequestURI(),stringBuilder); |
|||
e.printStackTrace(); |
|||
return R.error("数据不存在或被移除"); |
|||
} |
|||
|
|||
@ExceptionHandler({ |
|||
AccessDeniedException.class |
|||
}) |
|||
@ResponseBody |
|||
public R handleAccessException(AccessDeniedException e,HttpServletRequest request) { |
|||
HttpCode hc = HttpCode.FORBIDDEN_403; |
|||
log.error("访问拦截【{}】,请求地址:{}",e.getMessage(),request.getRequestURI()); |
|||
return new R(hc.getCode(),hc.getMsg()); |
|||
} |
|||
|
|||
@ExceptionHandler({ |
|||
UsernameNotFoundException.class, |
|||
}) |
|||
@ResponseBody |
|||
public R handlePrintMsgException(UsernameNotFoundException e) { |
|||
return R.error(); |
|||
} |
|||
|
|||
@ExceptionHandler({ |
|||
BadCredentialsException.class, |
|||
}) |
|||
@ResponseBody |
|||
public R handlePrintMsgException(Exception e) { |
|||
log.warn(e.getMessage()); |
|||
HttpCode hc = HttpCode.LOGIN_ERR_1; |
|||
return new R(hc.getCode(),hc.getMsg()); |
|||
} |
|||
|
|||
@ExceptionHandler({ |
|||
BindException.class, |
|||
HttpRequestMethodNotSupportedException.class |
|||
}) |
|||
@ResponseBody |
|||
public R handleDevPrintMsgException(Exception e,HttpServletRequest request) { |
|||
log.error("参数校验异常:{}",e.getMessage()); |
|||
if(DevEnvironmentConfig.isDev()){ |
|||
return R.error(e.getMessage()); |
|||
} |
|||
return R.error(); |
|||
} |
|||
|
|||
@ExceptionHandler({ |
|||
MethodArgumentNotValidException.class, |
|||
}) |
|||
@ResponseBody |
|||
public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e,HttpServletRequest request) { |
|||
log.error("参数校验异常【{}】,请求地址:{}",e.getMessage(),request.getRequestURI()); |
|||
return R.error(e.getBindingResult().getAllErrors().get(0).getDefaultMessage()); |
|||
} |
|||
|
|||
|
|||
@ExceptionHandler(value = DuplicateKeyException.class) |
|||
@ResponseBody |
|||
public R handleDuplicateKeyException(DuplicateKeyException e,HttpServletRequest request) { |
|||
log.error("限制重复数据【{}】,请求地址:{}",e.getMessage(),request.getRequestURI()); |
|||
e.printStackTrace(); |
|||
return R.error("限制重复数据,请联系管理员"); |
|||
} |
|||
|
|||
@ExceptionHandler(value = HttpMessageNotReadableException.class) |
|||
@ResponseBody |
|||
public R handleHttpMessageNotReadableException(HttpMessageNotReadableException e,HttpServletRequest request) { |
|||
log.error("请求参数无法解析【{}】,请求地址:{}",e.getMessage(),request.getRequestURI()); |
|||
return R.error("请求参数无法解析"); |
|||
} |
|||
|
|||
@ExceptionHandler({ |
|||
SQLIntegrityConstraintViolationException.class, |
|||
}) |
|||
@ResponseBody |
|||
public R handleSqlIntegrityException(Exception e,HttpServletRequest request) { |
|||
log.warn("数据库拦截【{}】,请求地址:{}",e.getMessage(),request.getRequestURI()); |
|||
e.printStackTrace(); |
|||
return new R(500,"数据库拦截,请联系管理员"); |
|||
} |
|||
|
|||
/** |
|||
* 强制运行写入成功 |
|||
* @param e |
|||
* @return |
|||
*/ |
|||
@ExceptionHandler(value = HttpMessageNotWritableException.class) |
|||
@ResponseBody |
|||
public R handleMsgException(HttpMessageNotWritableException e) { |
|||
return R.ok(); |
|||
} |
|||
|
|||
@ExceptionHandler(value = Exception.class) |
|||
@ResponseBody |
|||
public R handleException(Exception e,HttpServletRequest request) { |
|||
log.error("Servlet异常\n请求地址:{},异常类型:{}\n异常信息:{}\n异常体:",request.getRequestURI(),e.getClass().getSimpleName(),e.getMessage(),e); |
|||
e.printStackTrace(); |
|||
if(DevEnvironmentConfig.isDev()){return R.error(e.getMessage());} |
|||
return R.error(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,66 @@ |
|||
package com.qs.serve.common.framework.interceptor; |
|||
|
|||
import com.qs.serve.common.framework.redis.RedisService; |
|||
import com.qs.serve.common.model.HttpResponsePrintUtil; |
|||
import com.qs.serve.common.model.annotation.LimitSubmit; |
|||
import com.qs.serve.common.util.StringUtils; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.web.method.HandlerMethod; |
|||
import org.springframework.web.servlet.HandlerInterceptor; |
|||
|
|||
import javax.annotation.Resource; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.lang.reflect.Method; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
/** |
|||
* 防止重复提交拦截器 |
|||
* @author YenHex |
|||
*/ |
|||
@Configuration(proxyBeanMethods = false) |
|||
public class LimitSubmitInterceptor implements HandlerInterceptor { |
|||
|
|||
public final String REPEAT_Limit_KEY = "repeatLimitKey"; |
|||
|
|||
@Resource |
|||
public RedisService redisService; |
|||
|
|||
@Override |
|||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
|||
if (handler instanceof HandlerMethod) { |
|||
HandlerMethod handlerMethod = (HandlerMethod) handler; |
|||
Method method = handlerMethod.getMethod(); |
|||
LimitSubmit annotation = method.getAnnotation(LimitSubmit.class); |
|||
if (annotation != null) { |
|||
if (this.LimitSubmit(request, annotation)) { |
|||
if(StringUtils.isNotEmpty(annotation.message())){ |
|||
HttpResponsePrintUtil.print(response,406,annotation.message()); |
|||
}else { |
|||
HttpResponsePrintUtil.print(response,406,"系统处理中,请勿频繁操作"); |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} else { |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 验证是否重复提交由子类实现具体的防重复提交的规则 |
|||
* @param request 请求对象 |
|||
* @param annotation 防复注解 |
|||
* @return |
|||
*/ |
|||
public boolean LimitSubmit(HttpServletRequest request, LimitSubmit annotation) throws Exception { |
|||
String key = REPEAT_Limit_KEY+"_"+request.getRequestURI()+"_"+request.getRemoteHost(); |
|||
Object cache = redisService.get(key); |
|||
if(cache!=null){return true;} |
|||
redisService.set(key,"true",annotation.interval(), TimeUnit.MILLISECONDS); |
|||
return false; |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,29 @@ |
|||
package com.qs.serve.common.framework.interceptor; |
|||
|
|||
import com.alibaba.fastjson.serializer.JSONSerializer; |
|||
import com.alibaba.fastjson.serializer.ObjectSerializer; |
|||
|
|||
import java.io.IOException; |
|||
import java.lang.reflect.Type; |
|||
import java.time.LocalDateTime; |
|||
import java.time.format.DateTimeFormatter; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2024/7/18 |
|||
*/ |
|||
public class LocalDateTimeFormatSerializer implements ObjectSerializer { |
|||
|
|||
@Override |
|||
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { |
|||
if (object == null) { |
|||
serializer.out.writeNull(); |
|||
return; |
|||
} |
|||
LocalDateTime date = (LocalDateTime) object; |
|||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
|||
String timeString = formatter.format(date); |
|||
serializer.write(timeString); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,98 @@ |
|||
package com.qs.serve.common.framework.interceptor; |
|||
|
|||
import com.qs.serve.common.model.HttpResponsePrintUtil; |
|||
import com.qs.serve.common.model.annotation.RepeatSubmit; |
|||
import com.qs.serve.common.util.JsonUtil; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.web.method.HandlerMethod; |
|||
import org.springframework.web.servlet.HandlerInterceptor; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import javax.servlet.http.HttpSession; |
|||
import java.lang.reflect.Method; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 防止重复提交拦截器 |
|||
* @author YenHex |
|||
*/ |
|||
@Configuration(proxyBeanMethods = false) |
|||
public class RepeatSubmitInterceptor implements HandlerInterceptor { |
|||
|
|||
public final String REPEAT_PARAMS = "repeatParams"; |
|||
public final String REPEAT_TIME = "repeatTime"; |
|||
public final String SESSION_REPEAT_KEY = "repeatData"; |
|||
|
|||
@Override |
|||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
|||
if (handler instanceof HandlerMethod) { |
|||
HandlerMethod handlerMethod = (HandlerMethod) handler; |
|||
Method method = handlerMethod.getMethod(); |
|||
RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); |
|||
if (annotation != null) { |
|||
if (this.isRepeatSubmit(request, annotation)) { |
|||
HttpResponsePrintUtil.print(response,406,"系统正常处理,请勿重复提交"); |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} else { |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 验证是否重复提交由子类实现具体的防重复提交的规则 |
|||
* @param request 请求对象 |
|||
* @param annotation 防复注解 |
|||
* @return |
|||
*/ |
|||
public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) throws Exception { |
|||
// 本次参数及系统时间
|
|||
String nowParams = JsonUtil.objectToJson(request.getParameterMap()); |
|||
Map<String, Object> nowDataMap = new HashMap<String, Object>(); |
|||
nowDataMap.put(REPEAT_PARAMS, nowParams); |
|||
nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); |
|||
// 请求地址(作为存放session的key值)
|
|||
String url = request.getRequestURI(); |
|||
HttpSession session = request.getSession(); |
|||
Object sessionObj = session.getAttribute(SESSION_REPEAT_KEY); |
|||
if (sessionObj != null) { |
|||
Map<String, Object> sessionMap = (Map<String, Object>) sessionObj; |
|||
if (sessionMap.containsKey(url)) { |
|||
Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url); |
|||
if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval())) { |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
Map<String, Object> sessionMap = new HashMap<>(); |
|||
sessionMap.put(url, nowDataMap); |
|||
session.setAttribute(SESSION_REPEAT_KEY, sessionMap); |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* 判断参数是否相同 |
|||
*/ |
|||
private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap) { |
|||
String nowParams = (String) nowMap.get(REPEAT_PARAMS); |
|||
String preParams = (String) preMap.get(REPEAT_PARAMS); |
|||
return nowParams.equals(preParams); |
|||
} |
|||
|
|||
/** |
|||
* 判断两次间隔时间 |
|||
*/ |
|||
private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap, int interval) { |
|||
long time1 = (Long) nowMap.get(REPEAT_TIME); |
|||
long time2 = (Long) preMap.get(REPEAT_TIME); |
|||
if ((time1 - time2) < interval) { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,52 @@ |
|||
package com.qs.serve.common.framework.manager; |
|||
|
|||
import com.qs.serve.common.util.SpringUtils; |
|||
import com.qs.serve.common.util.ThreadsUtils; |
|||
|
|||
import java.util.TimerTask; |
|||
import java.util.concurrent.ScheduledExecutorService; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
|
|||
/** |
|||
* 异步任务管理器 |
|||
* @author YenHex |
|||
* @since 2022/2/24 |
|||
*/ |
|||
public class AsyncManager { |
|||
/** |
|||
* 操作延迟10毫秒 |
|||
*/ |
|||
private final int OPERATE_DELAY_TIME = 10; |
|||
|
|||
/** |
|||
* 异步操作任务调度线程池 |
|||
*/ |
|||
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService"); |
|||
|
|||
/** |
|||
* 单例模式 |
|||
*/ |
|||
private AsyncManager() { |
|||
} |
|||
|
|||
private static AsyncManager me = new AsyncManager(); |
|||
|
|||
public static AsyncManager me() { |
|||
return me; |
|||
} |
|||
|
|||
/** |
|||
* 执行任务 |
|||
* @param task 任务 |
|||
*/ |
|||
public void execute(TimerTask task) { |
|||
executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS); |
|||
} |
|||
|
|||
/** 停止任务线程池 */ |
|||
public void shutdown() { |
|||
ThreadsUtils.shutdownAndAwaitTermination(executor); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,17 @@ |
|||
package com.qs.serve.common.framework.mybatis.handler; |
|||
|
|||
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; |
|||
import com.qs.serve.common.util.NanoIdUtils; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/4/11 |
|||
*/ |
|||
public class IdGeneratorHandler extends DefaultIdentifierGenerator { |
|||
|
|||
@Override |
|||
public String nextUUID(Object entity) { |
|||
return NanoIdUtils.randomNanoId(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,50 @@ |
|||
package com.qs.serve.common.framework.mybatis.handler.meta; |
|||
|
|||
import cn.hutool.json.JSONUtil; |
|||
import org.apache.ibatis.type.BaseTypeHandler; |
|||
import org.apache.ibatis.type.JdbcType; |
|||
import org.apache.ibatis.type.MappedJdbcTypes; |
|||
import org.apache.ibatis.type.MappedTypes; |
|||
|
|||
import java.sql.CallableStatement; |
|||
import java.sql.PreparedStatement; |
|||
import java.sql.ResultSet; |
|||
import java.sql.SQLException; |
|||
|
|||
/** |
|||
* 存储到数据库, 将String数组转换成字符串; |
|||
* 从数据库获取数据, 将字符串转为LONG数组. |
|||
* @author YenHex |
|||
* @since 2022/3/1 |
|||
*/ |
|||
@MappedTypes({String[].class}) |
|||
@MappedJdbcTypes({JdbcType.VARCHAR}) |
|||
public class JsonStringTypeHandler extends BaseTypeHandler<String[]> { |
|||
|
|||
private static String[] l = new String[]{}; |
|||
|
|||
@Override |
|||
public void setNonNullParameter(PreparedStatement ps, int i, |
|||
String[] parameter, JdbcType jdbcType) throws SQLException { |
|||
ps.setString(i, JSONUtil.toJsonStr(parameter)); |
|||
} |
|||
|
|||
@Override |
|||
public String[] getNullableResult(ResultSet rs, String columnName) |
|||
throws SQLException { |
|||
return JSONUtil.parseArray(rs.getString(columnName)).toArray(l); |
|||
} |
|||
|
|||
@Override |
|||
public String[] getNullableResult(ResultSet rs, int columnIndex) |
|||
throws SQLException { |
|||
return JSONUtil.parseArray(rs.getString(columnIndex)).toArray(l); |
|||
} |
|||
|
|||
@Override |
|||
public String[] getNullableResult(CallableStatement cs, int columnIndex) |
|||
throws SQLException { |
|||
return JSONUtil.parseArray(cs.getString(columnIndex)).toArray(l); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,74 @@ |
|||
package com.qs.serve.common.framework.mybatis.handler.meta; |
|||
|
|||
import com.qs.serve.common.util.StringUtils; |
|||
import org.apache.ibatis.type.BaseTypeHandler; |
|||
import org.apache.ibatis.type.JdbcType; |
|||
import org.apache.ibatis.type.MappedJdbcTypes; |
|||
import org.apache.ibatis.type.MappedTypes; |
|||
|
|||
import java.sql.CallableStatement; |
|||
import java.sql.PreparedStatement; |
|||
import java.sql.ResultSet; |
|||
import java.sql.SQLException; |
|||
import java.util.Arrays; |
|||
|
|||
/** |
|||
* 存储到数据库, 将String数组转换成字符串; |
|||
* 从数据库获取数据, 将字符串转为LONG数组. |
|||
* @author YenHex |
|||
* @since 2022/3/1 |
|||
*/ |
|||
@MappedTypes({String[].class}) |
|||
@MappedJdbcTypes({JdbcType.VARCHAR}) |
|||
public class SplitStringTypeHandler extends BaseTypeHandler<String[]> { |
|||
|
|||
private static String[] l = new String[]{}; |
|||
|
|||
@Override |
|||
public void setNonNullParameter(PreparedStatement ps, int i, String[] parameter, JdbcType jdbcType) throws SQLException { |
|||
if(parameter!=null&¶meter.length>1){ |
|||
StringBuffer buffer = new StringBuffer(); |
|||
for (int i1 = 0; i1 < parameter.length; i1++) { |
|||
buffer.append(parameter[i1]); |
|||
if(i1+1<parameter.length){ |
|||
buffer.append(","); |
|||
} |
|||
} |
|||
ps.setString(i, buffer.toString()); |
|||
}else if (parameter!=null&¶meter.length==1){ |
|||
ps.setString(i, parameter[0]); |
|||
}else { |
|||
ps.setString(i, ""); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public String[] getNullableResult(ResultSet rs, String columnName) throws SQLException { |
|||
String valueString = rs.getString(columnName); |
|||
return initValues(valueString); |
|||
} |
|||
|
|||
@Override |
|||
public String[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException { |
|||
String valueString = rs.getString(columnIndex); |
|||
return initValues(valueString); |
|||
} |
|||
|
|||
@Override |
|||
public String[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { |
|||
String valueString = cs.getString(columnIndex); |
|||
return initValues(valueString); |
|||
} |
|||
|
|||
private String[] initValues(String valueString){ |
|||
if(StringUtils.isNotEmpty(valueString)){ |
|||
String[] vals = valueString.split(","); |
|||
return Arrays.stream(vals) |
|||
.filter(val -> val != null && val.trim().length() > 0) |
|||
.toArray(String[]::new); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,69 @@ |
|||
package com.qs.serve.common.framework.mybatis.handler.meta; |
|||
|
|||
import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 拓展表格名称 |
|||
* @author YenHex |
|||
* @since 2024/12/26 |
|||
*/ |
|||
@Slf4j |
|||
public class TableNameAppendHandler implements TableNameHandler { |
|||
|
|||
/** |
|||
* 用于记录哪些表可以使用该月份动态表名处理器(即哪些表按月分表) |
|||
*/ |
|||
private List<String> tableNames; |
|||
|
|||
/** |
|||
* 构造函数,构造动态表名处理器的时候,传递tableNames参数 |
|||
* @param tableNames |
|||
*/ |
|||
public TableNameAppendHandler(String ...tableNames) { |
|||
this.tableNames = Arrays.asList(tableNames); |
|||
} |
|||
|
|||
/** |
|||
* 每个请求线程维护一个month数据,避免多线程数据冲突。所以使用ThreadLocal |
|||
*/ |
|||
private static final ThreadLocal<String> APPEND_DATA = new ThreadLocal<>(); |
|||
|
|||
/** |
|||
* 设置请求线程的month数据 |
|||
* @param name |
|||
*/ |
|||
public static void setAppend(String name) { |
|||
APPEND_DATA.set(name); |
|||
} |
|||
|
|||
/** |
|||
* 删除当前请求线程的month数据 |
|||
*/ |
|||
public static void removeCache() { |
|||
APPEND_DATA.remove(); |
|||
} |
|||
|
|||
/** |
|||
* 动态表名接口实现方法 |
|||
* @param sql |
|||
* @param tableName |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public String dynamicTableName(String sql, String tableName) { |
|||
if (this.tableNames.contains(tableName) && APPEND_DATA.get() != null){ |
|||
//表名增加月份后缀
|
|||
return tableName + "_" + APPEND_DATA.get(); |
|||
}else{ |
|||
if(this.tableNames.contains(tableName)){ |
|||
log.warn("APPEND_DATA is null, table is {}",tableName); |
|||
} |
|||
//表名原样返回
|
|||
return tableName; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,115 @@ |
|||
package com.qs.serve.common.framework.mybatis.join; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.qs.serve.common.framework.mybatis.join.annotations.BindEntity; |
|||
import com.qs.serve.common.framework.mybatis.join.enums.JoinType; |
|||
import com.qs.serve.common.framework.mybatis.join.model.JoinFieldData; |
|||
import com.qs.serve.common.util.CollectionUtil; |
|||
import com.qs.serve.common.util.SpringUtils; |
|||
import com.qs.serve.common.util.WordUtil; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import java.lang.annotation.Annotation; |
|||
import java.lang.reflect.Field; |
|||
import java.util.ArrayList; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/5/24 |
|||
*/ |
|||
@Slf4j |
|||
public class JoinUtil { |
|||
|
|||
private static Map<String, List<JoinFieldData>> CACHE_MAP = new ConcurrentHashMap<>(); |
|||
|
|||
private static List<JoinFieldData> getJoinFields(List<?> list) { |
|||
if(CollectionUtil.isEmpty(list)){ |
|||
return new ArrayList<>(); |
|||
} |
|||
String className = list.get(0).getClass().getName(); |
|||
List<JoinFieldData> joinFieldDataList = new ArrayList<>(); |
|||
Class<?> clazz = null; |
|||
try { |
|||
clazz = Class.forName(className); |
|||
} catch (ClassNotFoundException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
if(clazz==null){return null;} |
|||
Field[] fields = clazz.getDeclaredFields(); |
|||
Field fieldJoinVal = null; |
|||
Field fieldSetVal = null; |
|||
BindEntity bindEntity = null; |
|||
for (Field field : fields) { |
|||
for (Annotation annotation : field.getAnnotations()) { |
|||
if(annotation instanceof BindEntity){ |
|||
fieldSetVal = field; |
|||
bindEntity = (BindEntity) annotation; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
if(fieldSetVal!=null){ |
|||
for (Field field :fields){ |
|||
if(field.getName().equals(bindEntity.joinField())){ |
|||
fieldJoinVal = field; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
if(bindEntity!=null&&fieldJoinVal!=null){ |
|||
JoinFieldData fieldData = new JoinFieldData(); |
|||
fieldData.setFieldJoinVal(fieldJoinVal); |
|||
fieldData.setBindEntity(bindEntity); |
|||
fieldData.setFieldSetVal(fieldSetVal); |
|||
joinFieldDataList.add(fieldData); |
|||
} |
|||
CACHE_MAP.put(className,joinFieldDataList); |
|||
return joinFieldDataList; |
|||
} |
|||
|
|||
public static void relate(List<?> list) { |
|||
List<JoinFieldData> joinFieldData = getJoinFields(list); |
|||
HashMap<String,Object> tempCache = new HashMap<>(list.size()+1); |
|||
for (JoinFieldData fieldData : joinFieldData) { |
|||
for (Object object : list) { |
|||
try { |
|||
Field fieldJoinVal = fieldData.getFieldJoinVal(); |
|||
Field fieldSetVal = fieldData.getFieldSetVal(); |
|||
BindEntity bindEntity = fieldData.getBindEntity(); |
|||
fieldSetVal.setAccessible(true); |
|||
fieldJoinVal.setAccessible(true); |
|||
IService<?> iService = SpringUtils.getBean(bindEntity.service()); |
|||
Object identity = fieldJoinVal.get(object); |
|||
if(identity==null){ |
|||
continue; |
|||
} |
|||
Object result = tempCache.get(identity.toString()); |
|||
if(result!=null){ |
|||
fieldSetVal.set(object,result); |
|||
continue; |
|||
} |
|||
if(bindEntity.joinType()== JoinType.List){ |
|||
QueryWrapper wrapper = new QueryWrapper<>(); |
|||
wrapper.eq(WordUtil.toLine(bindEntity.joinField()),identity); |
|||
result = iService.list(wrapper); |
|||
}else { |
|||
QueryWrapper wrapper = new QueryWrapper(); |
|||
wrapper.eq(WordUtil.toLine(bindEntity.selfField()),identity); |
|||
result = iService.getOne(wrapper,false); |
|||
} |
|||
fieldSetVal.set(object,result); |
|||
tempCache.put(identity.toString(),result); |
|||
} catch (IllegalAccessException e) { |
|||
log.warn("join 工具失败:",e); |
|||
} |
|||
} |
|||
} |
|||
tempCache = null; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,36 @@ |
|||
package com.qs.serve.common.framework.mybatis.join.annotations; |
|||
|
|||
import com.baomidou.mybatisplus.extension.service.IService; |
|||
import com.qs.serve.common.framework.mybatis.join.enums.JoinType; |
|||
|
|||
import java.lang.annotation.ElementType; |
|||
import java.lang.annotation.Retention; |
|||
import java.lang.annotation.RetentionPolicy; |
|||
import java.lang.annotation.Target; |
|||
|
|||
/** |
|||
* 实现left join |
|||
* @author YenHex |
|||
* @since 2022/5/24 |
|||
*/ |
|||
@Target({ElementType.FIELD}) |
|||
@Retention(RetentionPolicy.RUNTIME) |
|||
public @interface BindEntity { |
|||
|
|||
Class<? extends IService> service(); |
|||
|
|||
/** |
|||
* 关联的表 |
|||
* @return |
|||
*/ |
|||
String joinField() default ""; |
|||
|
|||
/** |
|||
* 主表 |
|||
* @return |
|||
*/ |
|||
String selfField() default "id"; |
|||
|
|||
JoinType joinType() default JoinType.Object; |
|||
|
|||
} |
@ -0,0 +1,14 @@ |
|||
package com.qs.serve.common.framework.mybatis.join.enums; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/5/24 |
|||
*/ |
|||
public enum JoinType { |
|||
|
|||
/** |
|||
* 返回类型 |
|||
*/ |
|||
Object,List |
|||
|
|||
} |
@ -0,0 +1,17 @@ |
|||
package com.qs.serve.common.framework.mybatis.join.model; |
|||
|
|||
import com.qs.serve.common.framework.mybatis.join.annotations.BindEntity; |
|||
import lombok.Data; |
|||
|
|||
import java.lang.reflect.Field; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/5/24 |
|||
*/ |
|||
@Data |
|||
public class JoinFieldData { |
|||
Field fieldJoinVal; |
|||
Field fieldSetVal; |
|||
BindEntity bindEntity; |
|||
} |
@ -0,0 +1,159 @@ |
|||
package com.qs.serve.common.framework.mybatis.query; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableField; |
|||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
|||
import com.qs.serve.common.framework.mybatis.query.annotations.QueryWrap; |
|||
import com.qs.serve.common.framework.mybatis.query.model.QueryFieldData; |
|||
import com.qs.serve.common.framework.mybatis.query.model.QueryFieldDataValue; |
|||
import com.qs.serve.common.framework.mybatis.query.model.QueryType; |
|||
import com.qs.serve.common.util.WordUtil; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.util.CollectionUtils; |
|||
import org.springframework.util.StringUtils; |
|||
|
|||
import java.lang.annotation.Annotation; |
|||
import java.lang.reflect.Field; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
|
|||
/** |
|||
* @author JcYen |
|||
* @Date 2017/10/28 |
|||
* @Version 1.0 |
|||
*/ |
|||
@Slf4j |
|||
public class AnnotationQueryStorage { |
|||
|
|||
private static final Map<String, List<QueryFieldData>> BEAN_QUERY_FIELD = new ConcurrentHashMap<>(); |
|||
|
|||
protected static List<QueryFieldData> getQueryFieldList(String className){ |
|||
List<QueryFieldData> queryFieldList = BEAN_QUERY_FIELD.get(className); |
|||
if(queryFieldList==null){ |
|||
Class<?> clazz = null; |
|||
try { |
|||
clazz = Class.forName(className); |
|||
} catch (ClassNotFoundException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
queryFieldList = new ArrayList<>(); |
|||
if(clazz==null){return queryFieldList;} |
|||
Field[] fields = clazz.getDeclaredFields(); |
|||
for (Field field : fields) { |
|||
Annotation[] annotations = field.getAnnotations(); |
|||
boolean isExist = false; |
|||
boolean isIgnore = false; |
|||
for (Annotation annotation : annotations) { |
|||
if(annotation instanceof QueryWrap){ |
|||
QueryWrap queryWrap = (QueryWrap)annotation; |
|||
QueryFieldData queryField= handleQueryField(queryWrap.type(),field); |
|||
if(queryField!=null){ |
|||
isExist = true; |
|||
queryFieldList.add(queryField); |
|||
break; |
|||
} |
|||
} |
|||
if(annotation instanceof TableField){ |
|||
TableField tableField = (TableField) annotation; |
|||
isIgnore = tableField.exist(); |
|||
} |
|||
} |
|||
//不存在,添加默认
|
|||
if( !isExist && !isIgnore ){ |
|||
QueryFieldData queryField = new QueryFieldData(); |
|||
//系统默认使用格式。示例: userInfo -> user_info
|
|||
queryField.setColumnName(WordUtil.toLine(field.getName())); |
|||
queryField.setField(field); |
|||
queryField.setFieldName(field.getName()); |
|||
queryField.setType(QueryType.NONE); |
|||
queryFieldList.add(queryField); |
|||
} |
|||
} |
|||
BEAN_QUERY_FIELD.put(className,queryFieldList); |
|||
if(queryFieldList.size()==0){ |
|||
log.warn("无匹配的注解字段,类名:"+className); |
|||
} |
|||
} |
|||
return queryFieldList; |
|||
} |
|||
|
|||
/** |
|||
* 处理查询列 |
|||
* @param queryType |
|||
* @param field |
|||
* @return |
|||
*/ |
|||
private static QueryFieldData handleQueryField(QueryType queryType, Field field){ |
|||
String columnName = null; |
|||
if(queryType!=null){ |
|||
QueryFieldData queryField = new QueryFieldData(); |
|||
if(StringUtils.isEmpty(columnName)){ |
|||
columnName = WordUtil.toLine(field.getName()); |
|||
} |
|||
queryField.setFieldName(field.getName()); |
|||
queryField.setColumnName(columnName); |
|||
queryField.setField(field); |
|||
queryField.setType(queryType); |
|||
return queryField; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 加载查询对象生成配置值 |
|||
* @param query |
|||
* @return |
|||
*/ |
|||
protected static List<QueryFieldDataValue> loadQueryFieldDataValues(Object query){ |
|||
String className = query.getClass().getName(); |
|||
List<QueryFieldData> dataList = AnnotationQueryStorage.getQueryFieldList(className); |
|||
if(!CollectionUtils.isEmpty(dataList)){ |
|||
List<QueryFieldDataValue> valueList = new ArrayList<>(); |
|||
for (QueryFieldData fieldData : dataList) { |
|||
Field field = fieldData.getField(); |
|||
field.setAccessible(true); |
|||
Object value = null; |
|||
try { |
|||
value = field.get(query); |
|||
} catch (IllegalAccessException e) { |
|||
log.warn("查询类字段参数异常。查询类:{},字段:{}",className,field.getName()); |
|||
} |
|||
if(value!=null){ |
|||
QueryFieldDataValue dataValue = new QueryFieldDataValue(fieldData); |
|||
//通过列条件,重新赋值(赋值查询条件和格式)
|
|||
dataValue.setValue(value); |
|||
valueList.add(dataValue); |
|||
} |
|||
} |
|||
return valueList; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* 初始化封装包参数 |
|||
* @param fieldValues |
|||
* @param queryWrapper |
|||
* @param <T> |
|||
* @return 判断是否排序 |
|||
*/ |
|||
protected static <T> void initWrap(List<QueryFieldDataValue> fieldValues, QueryWrapper<T> queryWrapper){ |
|||
for (QueryFieldDataValue fieldValue : fieldValues) { |
|||
QueryType queryType = fieldValue.getType(); |
|||
Object value = fieldValue.getValue(); |
|||
String column = fieldValue.getColumnName(); |
|||
if(queryType.equals(QueryType.EQ)){ queryWrapper.eq(column,value); } |
|||
if(queryType.equals(QueryType.GE)){ queryWrapper.ge(column,value); } |
|||
if(queryType.equals(QueryType.GT)){ queryWrapper.gt(column,value); } |
|||
if(queryType.equals(QueryType.In)){ queryWrapper.in(column,value); } |
|||
if(queryType.equals(QueryType.LE)){ queryWrapper.le(column,value); } |
|||
if(queryType.equals(QueryType.Like)){ queryWrapper.like(column,value); } |
|||
if(queryType.equals(QueryType.LT)){ queryWrapper.lt(column,value); } |
|||
if(queryType.equals(QueryType.NE)){ queryWrapper.ne(column,value); } |
|||
if(queryType.equals(QueryType.RightLike)){ queryWrapper.likeRight(column,value); } |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,32 @@ |
|||
package com.qs.serve.common.framework.mybatis.query.annotations; |
|||
|
|||
import com.qs.serve.common.framework.mybatis.query.model.QueryType; |
|||
|
|||
import java.lang.annotation.ElementType; |
|||
import java.lang.annotation.Retention; |
|||
import java.lang.annotation.RetentionPolicy; |
|||
import java.lang.annotation.Target; |
|||
|
|||
/** |
|||
* @author JcYen |
|||
* @date 2020/5/26 |
|||
* SQL In条件注解 |
|||
*/ |
|||
@Target({ElementType.FIELD}) |
|||
@Retention(RetentionPolicy.RUNTIME) |
|||
public @interface QueryWrap { |
|||
|
|||
/** |
|||
* 列名(默认为空字符串) |
|||
* 空字符串,采用字段转列策略 示例: userInfo -> user_info |
|||
* 非空时,采用列的值 |
|||
*/ |
|||
String value() default ""; |
|||
|
|||
/** |
|||
* 查询类型(默认采用值相对) |
|||
*/ |
|||
QueryType type() default QueryType.EQ; |
|||
|
|||
} |
|||
|
@ -0,0 +1,23 @@ |
|||
package com.qs.serve.common.framework.mybatis.query.model; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.lang.reflect.Field; |
|||
|
|||
/** |
|||
* 存储DTO |
|||
* @author JcYen |
|||
* @Date 2017/10/28 |
|||
* @Version 1.0 |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class QueryFieldData { |
|||
|
|||
private Field field; |
|||
private QueryType type; |
|||
private String columnName; |
|||
private String fieldName; |
|||
|
|||
} |
@ -0,0 +1,25 @@ |
|||
package com.qs.serve.common.framework.mybatis.query.model; |
|||
|
|||
import com.qs.serve.common.util.CopierUtil; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
/** |
|||
* 存储DTO |
|||
* @author JcYen |
|||
* @Date 2017/10/28 |
|||
* @Version 1.0 |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
public class QueryFieldDataValue{ |
|||
|
|||
public QueryFieldDataValue(QueryFieldData data){ |
|||
CopierUtil.copy(data,this); |
|||
} |
|||
|
|||
private QueryType type; |
|||
private String columnName; |
|||
private String fieldName; |
|||
private Object value; |
|||
} |
@ -0,0 +1,40 @@ |
|||
package com.qs.serve.common.framework.mybatis.query.model; |
|||
|
|||
/** |
|||
* @author JcYen |
|||
*/ |
|||
public enum QueryType { |
|||
|
|||
/** |
|||
* 无 |
|||
*/ |
|||
NONE, |
|||
|
|||
/** |
|||
* 通用的equals(Integer,Long,String) |
|||
*/ |
|||
EQ, |
|||
NE, |
|||
|
|||
/** |
|||
* 比较修饰符,修饰日期,数值类型(Integer,Long,Double,BigDecimal) |
|||
*/ |
|||
LT, |
|||
LE, |
|||
GT, |
|||
GE, |
|||
|
|||
/** |
|||
* 修饰List<Long> |
|||
*/ |
|||
In, |
|||
NotIn, |
|||
|
|||
/** |
|||
* 修饰字符串 |
|||
*/ |
|||
Like, |
|||
RightLike, |
|||
NotLike, |
|||
|
|||
} |
@ -0,0 +1,415 @@ |
|||
package com.qs.serve.common.framework.redis; |
|||
|
|||
import com.qs.serve.common.util.Assert; |
|||
import lombok.AllArgsConstructor; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Primary; |
|||
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.core.*; |
|||
import org.springframework.data.redis.serializer.RedisSerializationContext; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.*; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
/** |
|||
* @author JcYen |
|||
* @since 2022/3/4 |
|||
*/ |
|||
@Service |
|||
@AllArgsConstructor |
|||
public class RedisService { |
|||
|
|||
private final static ThreadLocal<String> RES_THEME_LOCK = new ThreadLocal<>(); |
|||
|
|||
public static void setLockTheme(String value){RES_THEME_LOCK.set(value);} |
|||
|
|||
public static String getLockTheme(){return RES_THEME_LOCK.get();} |
|||
|
|||
public static void removeThreadLocal(){ |
|||
RES_THEME_LOCK.remove(); |
|||
} |
|||
|
|||
@Bean |
|||
@Primary |
|||
public RedisCacheManager selfCacheManager(RedisTemplate<String, Object> redisTemplate) { |
|||
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory()); |
|||
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() |
|||
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer())); |
|||
return new TtlRedisCacheManager(redisCacheWriter, redisCacheConfiguration); |
|||
} |
|||
|
|||
private RedisTemplate redisTemplate; |
|||
|
|||
private StringRedisTemplate stringRedisTemplate; |
|||
|
|||
public long nextId(String key) { |
|||
ValueOperations<String, String> valueOps = redisTemplate.opsForValue(); |
|||
// 如果键不存在,则设置初始值为 "0"
|
|||
if (!redisTemplate.hasKey(key)) { |
|||
valueOps.set(key, "0"); |
|||
} |
|||
// 使用 INCR 命令递增计数器
|
|||
return valueOps.increment(key); |
|||
} |
|||
|
|||
/** |
|||
* 加锁 |
|||
* @param theme |
|||
* @param id |
|||
* @return 是否在锁 |
|||
*/ |
|||
public void throwResLock(String theme,String id){ |
|||
String key = "LOCK_RES:"+theme+":"+id; |
|||
String value = this.getString(key); |
|||
System.out.println("throwResLock:"+value); |
|||
String newVal = "lock"; |
|||
if(newVal.equals(value)){ |
|||
Assert.throwEx("服务正在处理,请稍后再试"); |
|||
} |
|||
this.set(key,newVal,10,TimeUnit.MINUTES); |
|||
String value2 = this.getString(key); |
|||
if(!newVal.equals(value2)){ |
|||
Assert.throwEx("锁失效"); |
|||
} |
|||
RedisService.setLockTheme(key); |
|||
} |
|||
|
|||
/** |
|||
* 释放锁 |
|||
* @param theme |
|||
* @param id |
|||
* @return 是否在锁 |
|||
*/ |
|||
public void removeResLock(String theme,String id){ |
|||
String key = "LOCK_RES:"+theme+":"+id; |
|||
this.remove(key); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 写入缓存 |
|||
* |
|||
* @param key |
|||
* @param value |
|||
* @return |
|||
*/ |
|||
public boolean set(final String key, Object value) { |
|||
boolean result = false; |
|||
try { |
|||
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); |
|||
operations.set(key, value); |
|||
result = true; |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* 写入缓存设置时效时间 |
|||
* |
|||
* @param key |
|||
* @param value |
|||
* @return |
|||
*/ |
|||
public boolean set(final String key, Object value, int expireTime) { |
|||
return set(key, value, expireTime,TimeUnit.SECONDS); |
|||
} |
|||
|
|||
/** |
|||
* 写入缓存设置时效时间 |
|||
* |
|||
* @param key |
|||
* @param value |
|||
* @return |
|||
*/ |
|||
public boolean set(final String key, Object value, int expireTime,TimeUnit unit) { |
|||
boolean result = false; |
|||
try { |
|||
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); |
|||
operations.set(key, value); |
|||
redisTemplate.expire(key, expireTime, unit); |
|||
result = true; |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* 批量删除对应的value |
|||
* |
|||
* @param keys |
|||
*/ |
|||
public void remove(final String... keys) { |
|||
for (String key : keys) { |
|||
remove(key); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 批量删除key |
|||
* |
|||
* @param pattern |
|||
*/ |
|||
public void removePattern(final String pattern) { |
|||
Set<Serializable> keys = redisTemplate.keys(pattern); |
|||
if (keys.size() > 0) |
|||
redisTemplate.delete(keys); |
|||
} |
|||
|
|||
/** |
|||
* 删除对应的value |
|||
* |
|||
* @param key |
|||
*/ |
|||
public void remove(final String key) { |
|||
if (exists(key)) { |
|||
redisTemplate.delete(key); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 判断缓存中是否有对应的value |
|||
* |
|||
* @param text |
|||
* @return |
|||
*/ |
|||
public Set<String> list(final String text) { |
|||
Set<String> keySet = redisTemplate.keys("*" + text + "*"); |
|||
for (String key : keySet) { |
|||
System.out.println(key); |
|||
} |
|||
return keySet; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取所有数据 |
|||
* |
|||
* @return |
|||
*/ |
|||
public Set<String> list() { |
|||
Set<String> keySet = redisTemplate.keys("*" + "#" +"*"); |
|||
for (String key : keySet) { |
|||
System.out.println(key); |
|||
} |
|||
return keySet; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 判断缓存中是否有对应的value |
|||
* |
|||
* @param text |
|||
* @return |
|||
*/ |
|||
public void removeForLike(final String text) { |
|||
Set<String> keySet = redisTemplate.keys("*" + text + "*"); |
|||
Iterator<String> it = keySet.iterator(); |
|||
while(it.hasNext()){ |
|||
redisTemplate.delete(it.next()); |
|||
} |
|||
} |
|||
|
|||
|
|||
public Map<String, Object> cleanRedis() { |
|||
Map<String, Object> map = new HashMap<>(); |
|||
try { |
|||
// 获取所有key
|
|||
Set<String> keys = redisTemplate.keys("*"); |
|||
assert keys != null; |
|||
// 迭代
|
|||
Iterator<String> it1 = keys.iterator(); |
|||
while (it1.hasNext()) { |
|||
// 循环删除
|
|||
stringRedisTemplate.delete(it1.next()); |
|||
} |
|||
map.put("code", 1); |
|||
map.put("msg", "清理全局缓存成功"); |
|||
return map; |
|||
} catch (Exception e) { |
|||
map.put("code", -1); |
|||
map.put("msg", "清理全局缓存失败"); |
|||
return map; |
|||
} |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 判断缓存中是否有对应的value |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public boolean exists(final String key) { |
|||
return redisTemplate.hasKey(key); |
|||
} |
|||
|
|||
/** |
|||
* 读取缓存 |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public Object get(final String key) { |
|||
Object result = null; |
|||
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); |
|||
result = operations.get(key); |
|||
return result; |
|||
} |
|||
|
|||
public String getString(final String key) { |
|||
Object result = null; |
|||
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); |
|||
result = operations.get(key); |
|||
if(result!=null){ |
|||
return result.toString(); |
|||
|
|||
} |
|||
return null; |
|||
} |
|||
|
|||
public Integer getInteger(final String key) { |
|||
String result = getString(key); |
|||
if(result!=null){ |
|||
return Integer.parseInt(result); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
public Long getLong(final String key) { |
|||
String result = getString(key); |
|||
if(result!=null){ |
|||
return Long.parseLong(result); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* 哈希 添加 |
|||
* |
|||
* @param key |
|||
* @param hashKey |
|||
* @param value |
|||
*/ |
|||
public void hmSet(String key, Object hashKey, Object value) { |
|||
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash(); |
|||
hash.put(key, hashKey, value); |
|||
} |
|||
|
|||
/** |
|||
* 哈希获取数据 |
|||
* |
|||
* @param key |
|||
* @param hashKey |
|||
* @return |
|||
*/ |
|||
public Object hmGet(String key, Object hashKey) { |
|||
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash(); |
|||
return hash.get(key, hashKey); |
|||
} |
|||
|
|||
/** |
|||
* 列表添加 |
|||
* |
|||
* @param k |
|||
* @param v |
|||
*/ |
|||
public void lPush(String k, Object v) { |
|||
ListOperations<String, Object> list = redisTemplate.opsForList(); |
|||
list.rightPush(k, v); |
|||
} |
|||
|
|||
/** |
|||
* 列表获取 |
|||
* |
|||
* @param k |
|||
* @param l |
|||
* @param l1 |
|||
* @return |
|||
*/ |
|||
public List<Object> lRange(String k, long l, long l1) { |
|||
ListOperations<String, Object> list = redisTemplate.opsForList(); |
|||
return list.range(k, l, l1); |
|||
} |
|||
|
|||
/** |
|||
* 集合添加 |
|||
* |
|||
* @param key |
|||
* @param value |
|||
*/ |
|||
public void add(String key, Object value) { |
|||
SetOperations<String, Object> set = redisTemplate.opsForSet(); |
|||
set.add(key, value); |
|||
} |
|||
|
|||
/** |
|||
* 集合获取 |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public Set<Object> setMembers(String key) { |
|||
SetOperations<String, Object> set = redisTemplate.opsForSet(); |
|||
return set.members(key); |
|||
} |
|||
|
|||
/** |
|||
* 有序集合添加 |
|||
* |
|||
* @param key |
|||
* @param value |
|||
* @param scoure |
|||
*/ |
|||
public void zAdd(String key, Object value, double scoure) { |
|||
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet(); |
|||
zset.add(key, value, scoure); |
|||
} |
|||
|
|||
/** |
|||
* 有序集合获取 |
|||
* |
|||
* @param key |
|||
* @param scoure |
|||
* @param scoure1 |
|||
* @return |
|||
*/ |
|||
public Set<Object> rangeByScore(String key, double scoure, double scoure1) { |
|||
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet(); |
|||
return zset.rangeByScore(key, scoure, scoure1); |
|||
} |
|||
|
|||
/** |
|||
* 移除业务锁 |
|||
* @param code |
|||
* @param targetId |
|||
*/ |
|||
public void removeLock(String code,String targetId){ |
|||
String key = "lock_commit:"+code+":"+targetId; |
|||
this.remove(key); |
|||
} |
|||
|
|||
/** |
|||
* 锁 |
|||
* @param code |
|||
* @param targetId |
|||
* @return true--新建锁成功,false反之 |
|||
*/ |
|||
public boolean tryToLock(String code,String targetId){ |
|||
String key = "lock_commit:"+code+":"+targetId; |
|||
Integer existState = getInteger(key); |
|||
if(existState==null){ |
|||
this.set(key,1,20,TimeUnit.SECONDS); |
|||
return true; |
|||
}else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,30 @@ |
|||
package com.qs.serve.common.framework.redis; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.data.redis.cache.RedisCache; |
|||
import org.springframework.data.redis.cache.RedisCacheConfiguration; |
|||
import org.springframework.data.redis.cache.RedisCacheManager; |
|||
import org.springframework.data.redis.cache.RedisCacheWriter; |
|||
import org.springframework.util.StringUtils; |
|||
|
|||
import java.time.Duration; |
|||
|
|||
@Slf4j |
|||
public class TtlRedisCacheManager extends RedisCacheManager { |
|||
public TtlRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) { |
|||
super(cacheWriter, defaultCacheConfiguration); |
|||
} |
|||
|
|||
@Override |
|||
protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) { |
|||
log.debug("TtlRedisCacheManager keyName:{}",name); |
|||
String[] cells = StringUtils.delimitedListToStringArray(name, "="); |
|||
name = cells[0]; |
|||
if (cells.length > 1) { |
|||
long ttl = Long.parseLong(cells[1]); |
|||
// 根据传参设置缓存失效时间,默认单位是秒
|
|||
cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl)); |
|||
} |
|||
return super.createRedisCache(name, cacheConfig); |
|||
} |
|||
} |
@ -0,0 +1,22 @@ |
|||
package com.qs.serve.common.framework.security.handler; |
|||
|
|||
import com.qs.serve.common.model.HttpResponsePrintUtil; |
|||
import org.springframework.security.access.AccessDeniedException; |
|||
import org.springframework.security.web.access.AccessDeniedHandler; |
|||
|
|||
import javax.servlet.ServletException; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/3/3 |
|||
*/ |
|||
public class SecurityAccessDeniedHandler implements AccessDeniedHandler { |
|||
|
|||
@Override |
|||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { |
|||
HttpResponsePrintUtil.print(response,403,"权限不足"); |
|||
} |
|||
} |
@ -0,0 +1,22 @@ |
|||
package com.qs.serve.common.framework.security.handler; |
|||
|
|||
import com.qs.serve.common.model.HttpResponsePrintUtil; |
|||
import org.springframework.security.core.AuthenticationException; |
|||
import org.springframework.security.web.authentication.AuthenticationFailureHandler; |
|||
|
|||
import javax.servlet.ServletException; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/3/3 |
|||
*/ |
|||
public class SecurityAuthenticationFailureHandler implements AuthenticationFailureHandler { |
|||
|
|||
@Override |
|||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException { |
|||
HttpResponsePrintUtil.print(response,401,"登录信息已过期或失效"); |
|||
} |
|||
} |
@ -0,0 +1,97 @@ |
|||
package com.qs.serve.common.framework.security.model; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import org.springframework.security.core.GrantedAuthority; |
|||
import org.springframework.security.core.authority.SimpleGrantedAuthority; |
|||
import org.springframework.security.core.userdetails.UserDetails; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 用户登录信息 |
|||
* @author YenHex |
|||
* @since 2022/3/1 |
|||
*/ |
|||
@Data |
|||
@AllArgsConstructor |
|||
public class LoginUser implements UserDetails { |
|||
|
|||
private String userId; |
|||
|
|||
private String nick; |
|||
|
|||
private String password; |
|||
|
|||
private String loginIp; |
|||
|
|||
/** 用户类型 */ |
|||
private LoginUserType typeFlag; |
|||
|
|||
private List<String> authorList; |
|||
private List<String> authorIds; |
|||
|
|||
private String tenant; |
|||
|
|||
@Override |
|||
public Collection<? extends GrantedAuthority> getAuthorities() { |
|||
if(authorList!=null&&authorList.size()>0){ |
|||
return authorList |
|||
.stream() |
|||
.filter(n->n.length()>0) |
|||
.map(auth->new SimpleGrantedAuthority("ROLE_"+auth)) |
|||
.collect(Collectors.toList()); |
|||
} |
|||
return Collections.singletonList(new SimpleGrantedAuthority("NOT_ROLE")); |
|||
} |
|||
|
|||
@Override |
|||
public String getPassword() { |
|||
return password; |
|||
} |
|||
|
|||
@Override |
|||
public String getUsername() { |
|||
return userId; |
|||
} |
|||
|
|||
@Override |
|||
public boolean isAccountNonExpired() { |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public boolean isAccountNonLocked() { |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public boolean isCredentialsNonExpired() { |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public boolean isEnabled() { |
|||
return true; |
|||
} |
|||
|
|||
public LoginUserDTO loginUserDTO(){ |
|||
return new LoginUserDTO(userId,nick,password,loginIp,typeFlag.getCode(),authorList,authorIds,tenant); |
|||
} |
|||
|
|||
public boolean verifyRole(String permitCode){ |
|||
return authorList.contains(permitCode); |
|||
} |
|||
|
|||
/** |
|||
* 是否拥有招生超管权限 |
|||
* @return |
|||
*/ |
|||
public boolean hasRegSuperRole(){ |
|||
return verifyRole("edu:reg:admin"); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,37 @@ |
|||
package com.qs.serve.common.framework.security.model; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 用户登录信息 |
|||
* @author YenHex |
|||
* @since 2022/3/1 |
|||
*/ |
|||
@Data |
|||
@NoArgsConstructor |
|||
@AllArgsConstructor |
|||
public class LoginUserDTO { |
|||
|
|||
private String userId; |
|||
|
|||
private String nick; |
|||
|
|||
private String password; |
|||
|
|||
private String loginIp; |
|||
|
|||
private String typeFlagCode; |
|||
|
|||
private List<String> authorList; |
|||
private List<String> authorIds; |
|||
private String tenant; |
|||
|
|||
public LoginUser loginUser(){ |
|||
return new LoginUser(userId,nick,password,loginIp,LoginUserType.getByCode(typeFlagCode),authorList,authorIds,tenant); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,34 @@ |
|||
package com.qs.serve.common.framework.security.model; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Getter; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/3/7 |
|||
*/ |
|||
@Getter |
|||
@AllArgsConstructor |
|||
public enum LoginUserType { |
|||
|
|||
/** |
|||
* 人员分类 |
|||
*/ |
|||
APP_USER("00","微信用户"), |
|||
SYS_USER("01","系统人员"), |
|||
SYS_SUP_USER("02","超级管理员") |
|||
; |
|||
|
|||
private String code; |
|||
private String name; |
|||
|
|||
public static LoginUserType getByCode(String code){ |
|||
for (LoginUserType value : LoginUserType.values()) { |
|||
if(value.getCode().equals(code)){ |
|||
return value; |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,28 @@ |
|||
package com.qs.serve.common.framework.security.util; |
|||
|
|||
/** |
|||
* @Author JcYen |
|||
* @Date 2021/9/24 |
|||
* @Version 1.0 |
|||
*/ |
|||
public class SecurityPermitUtil { |
|||
|
|||
public static boolean verify(String reg, String input){ |
|||
if ("/*".equals(reg)) return true; |
|||
String[] reg_split = reg.split("\\*"); |
|||
int index = 0, reg_len = reg_split.length; |
|||
boolean b = reg.charAt(reg.length() - 1) == '*' ? true : false; |
|||
while (input.length() > 0) { |
|||
if (index == reg_len) { |
|||
if (b) return true; |
|||
else return false; |
|||
} |
|||
String r = reg_split[index++]; |
|||
int indexOf = input.indexOf(r); |
|||
if (indexOf != 0) return false; |
|||
input = input.substring(indexOf + r.length()); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,18 @@ |
|||
package com.qs.serve.common.model; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.math.BigDecimal; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/7/31 |
|||
*/ |
|||
@Data |
|||
public class AmountDTO { |
|||
|
|||
private String id; |
|||
|
|||
private BigDecimal amount; |
|||
|
|||
} |
@ -0,0 +1,34 @@ |
|||
package com.qs.serve.common.model; |
|||
|
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2022/3/30 |
|||
*/ |
|||
public class HttpResponsePrintUtil { |
|||
|
|||
public static void print(HttpServletResponse response,Integer code ,String msg) throws IOException,SecurityException{ |
|||
response.setHeader("Access-Control-Allow-Origin", "*"); |
|||
response.setHeader("Access-Control-Allow-Credentials", "true"); |
|||
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS"); |
|||
response.setHeader("Access-Control-Max-Age", "86400"); |
|||
response.setHeader("Access-Control-Allow-Headers", "*"); |
|||
response.setStatus(200); |
|||
response.setCharacterEncoding("UTF-8"); |
|||
response.setCharacterEncoding("UTF-8"); |
|||
response.setContentType("application/json;charset=UTF-8"); |
|||
response.getWriter().print("{\"status\":"+code+",\"msg\":\""+msg+"\"}"); |
|||
response.getWriter().flush(); |
|||
} |
|||
|
|||
public static void print2(HttpServletResponse response,Integer code ,String msg)throws IOException,SecurityException{ |
|||
response.setCharacterEncoding("UTF-8"); |
|||
response.setContentType("application/json;charset=UTF-8"); |
|||
response.getWriter().print("{\"status\":"+code+",\"msg\":\""+msg+"\"}"); |
|||
response.getWriter().flush(); |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,20 @@ |
|||
package com.qs.serve.common.model.annotation; |
|||
|
|||
import java.lang.annotation.*; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/4/25 |
|||
*/ |
|||
@Target({ElementType.FIELD}) |
|||
@Retention(RetentionPolicy.RUNTIME) |
|||
@Documented |
|||
public @interface BusinessDifference { |
|||
|
|||
/** |
|||
* 字段备注 |
|||
* @return |
|||
*/ |
|||
String value() default ""; |
|||
|
|||
} |
@ -0,0 +1,25 @@ |
|||
package com.qs.serve.common.model.annotation; |
|||
|
|||
import java.lang.annotation.*; |
|||
|
|||
/** |
|||
* 防止表单重复提交 |
|||
* @author YenHex |
|||
* @since 2022-03-01 |
|||
*/ |
|||
@Target({ElementType.METHOD}) |
|||
@Retention(RetentionPolicy.RUNTIME) |
|||
@Documented |
|||
public @interface LimitSubmit { |
|||
|
|||
/** |
|||
* 间隔时间(ms),在世界间隔内超过执行次数,视为被限制 |
|||
*/ |
|||
int interval() default 1000; |
|||
|
|||
/** |
|||
* 提示消息 |
|||
*/ |
|||
String message() default ""; |
|||
|
|||
} |
@ -0,0 +1,20 @@ |
|||
package com.qs.serve.common.model.annotation; |
|||
|
|||
/** |
|||
* 防止表单重复提交 |
|||
* @author YenHex |
|||
* @since 2022-03-01 |
|||
*/ |
|||
public @interface RepeatSubmit { |
|||
|
|||
/** |
|||
* 间隔时间(ms),小于此时间视为重复提交 |
|||
*/ |
|||
int interval() default 5000; |
|||
|
|||
/** |
|||
* 提示消息 |
|||
*/ |
|||
String message() default "不允许重复提交,请稍后再试"; |
|||
|
|||
} |
@ -0,0 +1,35 @@ |
|||
package com.qs.serve.common.model.annotation; |
|||
|
|||
import com.qs.serve.common.model.enums.BizType; |
|||
import com.qs.serve.common.model.enums.InterType; |
|||
import com.qs.serve.common.model.enums.SystemModule; |
|||
|
|||
import java.lang.annotation.*; |
|||
|
|||
/** |
|||
* 记录用户登录操作 |
|||
* @author YenHex |
|||
* @since 2022-03-01 |
|||
*/ |
|||
@Target({ElementType.METHOD}) |
|||
@Retention(RetentionPolicy.RUNTIME) |
|||
@Documented |
|||
public @interface SysLog { |
|||
|
|||
SystemModule module() default SystemModule.SYSTEM; |
|||
|
|||
/** 业务标题 */ |
|||
String title() default ""; |
|||
|
|||
/** 操作描述 */ |
|||
String desc() default ""; |
|||
|
|||
/** 操作类型 */ |
|||
BizType biz() default BizType.OTHER; |
|||
|
|||
/** 接口类型 */ |
|||
InterType inter() default InterType.ADMIN; |
|||
|
|||
boolean saveReqParam() default true; |
|||
|
|||
} |
@ -0,0 +1,19 @@ |
|||
package com.qs.serve.common.model.chart; |
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/6/7 |
|||
*/ |
|||
@Data |
|||
public class BiCommonCounter { |
|||
|
|||
/** |
|||
* 横轴下标的ID |
|||
*/ |
|||
private String label; |
|||
|
|||
private Long counts; |
|||
|
|||
} |
@ -0,0 +1,15 @@ |
|||
package com.qs.serve.common.model.chart; |
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/6/7 |
|||
*/ |
|||
@Data |
|||
public class BiMonthCounter { |
|||
|
|||
private String months; |
|||
private Long counts; |
|||
|
|||
} |
@ -0,0 +1,39 @@ |
|||
package com.qs.serve.common.model.chart; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/6/7 |
|||
*/ |
|||
@Data |
|||
public class ChartAxisColumn { |
|||
|
|||
/** 列Id */ |
|||
String columnId; |
|||
|
|||
/** 列名 */ |
|||
String columnName; |
|||
|
|||
/** 系列坐标值合计 */ |
|||
Double total; |
|||
|
|||
public static List<ChartAxisColumn> buildMonthsOfYear(){ |
|||
List<ChartAxisColumn> axisColumnList = new ArrayList<>(); |
|||
for (long i = 1; i < 13; i++) { |
|||
ChartAxisColumn axisColumn = new ChartAxisColumn(); |
|||
if(i>9){ |
|||
axisColumn.setColumnId(i+""); |
|||
}else { |
|||
axisColumn.setColumnId("0"+i); |
|||
} |
|||
axisColumn.setColumnName(i+"月"); |
|||
axisColumnList.add(axisColumn); |
|||
} |
|||
return axisColumnList; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,148 @@ |
|||
package com.qs.serve.common.model.chart; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/6/7 |
|||
*/ |
|||
@Data |
|||
public class ChartDataVo { |
|||
|
|||
/** |
|||
* 列(饼状图的主要参数) |
|||
*/ |
|||
List<ChartAxisColumn> axisColumnList; |
|||
|
|||
/** |
|||
* 系列 |
|||
*/ |
|||
List<ChartSeriesItem> seriesItemList; |
|||
|
|||
/** |
|||
* 分组 |
|||
*/ |
|||
List<ChartGroupItem> groupItemList; |
|||
|
|||
|
|||
public void initAxisColumnTotal(){ |
|||
for (int i = 0; i < axisColumnList.size(); i++) { |
|||
ChartAxisColumn axisColumn = axisColumnList.get(i); |
|||
BigDecimal total = BigDecimal.ZERO; |
|||
if(seriesItemList!=null&&seriesItemList.size()>0){ |
|||
for (ChartSeriesItem seriesItem : seriesItemList) { |
|||
double value = seriesItem.getValues().get(i); |
|||
total = total.add(new BigDecimal(value+"")); |
|||
} |
|||
} |
|||
axisColumn.setTotal(total.doubleValue()); |
|||
} |
|||
} |
|||
|
|||
public static ChartDataVo buildStateChartData(List<BiCommonCounter> stateCounterList, Map<String,String> stateMap){ |
|||
ChartDataVo chartDataVo = new ChartDataVo(); |
|||
List<ChartAxisColumn> axisColumnList = new ArrayList<>(); |
|||
List<ChartSeriesItem> seriesItemList = new ArrayList<>(); |
|||
List<ChartGroupItem> groupItemList = new ArrayList<>(); |
|||
ChartGroupItem groupItem = new ChartGroupItem(); |
|||
groupItem.setGroupId(100L); |
|||
groupItem.setGroupName("默认"); |
|||
groupItemList.add(groupItem); |
|||
for (String stateNum : stateMap.keySet()) { |
|||
String label = stateMap.get(stateNum); |
|||
ChartAxisColumn axisColumn = new ChartAxisColumn(); |
|||
axisColumn.setColumnId(stateNum); |
|||
axisColumn.setColumnName(label); |
|||
axisColumnList.add(axisColumn); |
|||
} |
|||
List<Double> values = new ArrayList<>(); |
|||
for (ChartAxisColumn chartAxisColumn : axisColumnList) { |
|||
Double currVal = 0.0; |
|||
for (BiCommonCounter counter : stateCounterList) { |
|||
if(chartAxisColumn.getColumnId().equals(counter.getLabel())){ |
|||
currVal = counter.getCounts().doubleValue(); |
|||
break; |
|||
} |
|||
} |
|||
values.add(currVal); |
|||
} |
|||
ChartSeriesItem seriesItem = new ChartSeriesItem(); |
|||
seriesItem.setGroupId(groupItem.getGroupId()); |
|||
seriesItem.setGroupName(groupItem.getGroupName()); |
|||
seriesItem.setValues(values); |
|||
seriesItemList.add(seriesItem); |
|||
//更新total
|
|||
chartDataVo.setAxisColumnList(axisColumnList); |
|||
chartDataVo.setGroupItemList(groupItemList); |
|||
chartDataVo.setSeriesItemList(seriesItemList); |
|||
chartDataVo.initAxisColumnTotal(); |
|||
return chartDataVo; |
|||
} |
|||
|
|||
public void tes(){ |
|||
|
|||
} |
|||
|
|||
public void buildStateMap(Map<String,String> stateMap){ |
|||
init(); |
|||
for (String stateNum : stateMap.keySet()) { |
|||
String label = stateMap.get(stateNum); |
|||
ChartAxisColumn axisColumn = new ChartAxisColumn(); |
|||
axisColumn.setColumnId(stateNum); |
|||
axisColumn.setColumnName(label); |
|||
this.axisColumnList.add(axisColumn); |
|||
} |
|||
} |
|||
public void buildStateMapOfMonths(){ |
|||
init(); |
|||
this.axisColumnList = ChartAxisColumn.buildMonthsOfYear(); |
|||
} |
|||
|
|||
/** |
|||
* 先调用buildStateMap |
|||
* @param groupId |
|||
* @param groupName |
|||
* @param stateCounterList |
|||
*/ |
|||
public void addData(Long groupId,String groupName,List<BiCommonCounter> stateCounterList){ |
|||
ChartGroupItem groupItem = new ChartGroupItem(); |
|||
groupItem.setGroupId(groupId); |
|||
groupItem.setGroupName(groupName); |
|||
groupItemList.add(groupItem); |
|||
List<Double> values = new ArrayList<>(); |
|||
for (ChartAxisColumn chartAxisColumn : axisColumnList) { |
|||
Double currVal = 0.0; |
|||
for (BiCommonCounter counter : stateCounterList) { |
|||
if(chartAxisColumn.getColumnId().equals(counter.getLabel())){ |
|||
currVal = counter.getCounts().doubleValue(); |
|||
break; |
|||
} |
|||
} |
|||
values.add(currVal); |
|||
} |
|||
ChartSeriesItem seriesItem = new ChartSeriesItem(); |
|||
seriesItem.setGroupId(groupItem.getGroupId()); |
|||
seriesItem.setGroupName(groupItem.getGroupName()); |
|||
seriesItem.setValues(values); |
|||
seriesItemList.add(seriesItem); |
|||
this.initAxisColumnTotal(); |
|||
} |
|||
|
|||
private void init(){ |
|||
if(axisColumnList==null){ |
|||
axisColumnList = new ArrayList<>(); |
|||
} |
|||
if(seriesItemList==null){ |
|||
seriesItemList = new ArrayList<>(); |
|||
} |
|||
if(groupItemList==null){ |
|||
groupItemList = new ArrayList<>(); |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,18 @@ |
|||
package com.qs.serve.common.model.chart; |
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/6/7 |
|||
*/ |
|||
@Data |
|||
public class ChartGroupItem { |
|||
|
|||
/** 组id */ |
|||
private Long groupId; |
|||
|
|||
/** 组名 */ |
|||
private String groupName; |
|||
|
|||
} |
@ -0,0 +1,26 @@ |
|||
package com.qs.serve.common.model.chart; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/6/7 |
|||
*/ |
|||
@Data |
|||
public class ChartSeriesItem { |
|||
|
|||
|
|||
/** 组id */ |
|||
Long groupId; |
|||
|
|||
/** 组名 */ |
|||
String groupName; |
|||
|
|||
/** |
|||
* 值列表(列对应axisColumns) |
|||
*/ |
|||
List<Double> values; |
|||
|
|||
} |
@ -0,0 +1,75 @@ |
|||
package com.qs.serve.common.model.chart; |
|||
|
|||
import com.qs.serve.common.util.JsonUtil; |
|||
|
|||
import java.math.BigDecimal; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.Random; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/2/17 |
|||
*/ |
|||
public class PrintChart { |
|||
|
|||
|
|||
public static void main(String[] args) { |
|||
|
|||
//eg. 统计最近5年入学人数,并区分男女数量
|
|||
ChartDataVo chartDataVo = new ChartDataVo(); |
|||
|
|||
List<ChartAxisColumn> axisColumnList = new ArrayList<>(); |
|||
List<ChartSeriesItem> seriesItemList = new ArrayList<>(); |
|||
List<ChartGroupItem> groupItemList = new ArrayList<>(); |
|||
|
|||
ChartGroupItem groupItem = new ChartGroupItem(); |
|||
groupItem.setGroupId(100L); |
|||
groupItem.setGroupName("男学生"); |
|||
groupItemList.add(groupItem); |
|||
|
|||
ChartGroupItem groupItem2 = new ChartGroupItem(); |
|||
groupItem2.setGroupId(200L); |
|||
groupItem2.setGroupName("女学生"); |
|||
groupItemList.add(groupItem2); |
|||
|
|||
for (long i = 1; i <= 5; i++) { |
|||
ChartAxisColumn axisColumn = new ChartAxisColumn(); |
|||
axisColumn.setColumnId(i+""); |
|||
axisColumn.setColumnName("202"+i+"年"); |
|||
axisColumnList.add(axisColumn); |
|||
} |
|||
|
|||
Random random = new Random(); |
|||
for (ChartGroupItem chartGroupItem : groupItemList) { |
|||
ChartSeriesItem seriesItem = new ChartSeriesItem(); |
|||
seriesItem.setGroupId(chartGroupItem.getGroupId()); |
|||
seriesItem.setGroupName(chartGroupItem.getGroupName()); |
|||
List<Double> values = new ArrayList<>(); |
|||
for (int i = 0; i < axisColumnList.size(); i++) { |
|||
double result = random.nextInt(1000)+3000; |
|||
values.add(result); |
|||
} |
|||
seriesItem.setValues(values); |
|||
seriesItemList.add(seriesItem); |
|||
} |
|||
//更新total
|
|||
for (int i = 0; i < axisColumnList.size(); i++) { |
|||
ChartAxisColumn axisColumn = axisColumnList.get(i); |
|||
BigDecimal total = BigDecimal.ZERO; |
|||
for (ChartSeriesItem seriesItem : seriesItemList) { |
|||
double value = seriesItem.getValues().get(i); |
|||
total = total.add(new BigDecimal(value+"")); |
|||
} |
|||
axisColumn.setTotal(total.doubleValue()); |
|||
} |
|||
chartDataVo.setAxisColumnList(axisColumnList); |
|||
chartDataVo.setGroupItemList(groupItemList); |
|||
chartDataVo.setSeriesItemList(seriesItemList); |
|||
String v = JsonUtil.objectToJson(chartDataVo); |
|||
System.out.println(v); |
|||
} |
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,13 @@ |
|||
package com.qs.serve.common.model.consts; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2023/9/19 |
|||
*/ |
|||
public interface ApplyTypeConst { |
|||
|
|||
String CostBill = "CostBill"; |
|||
String CheckCost = "CheckCost"; |
|||
String ReleasePolicy = "ReleasePolicy"; |
|||
|
|||
} |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue