This commit is contained in:
张良(004796)
2023-12-20 21:40:09 +08:00
parent a3d488ac73
commit 346fbb494e
242 changed files with 388 additions and 41827 deletions

View File

@@ -328,8 +328,6 @@
<module>ruoyi-job</module>
<module>ruoyi-generator</module>
<module>ruoyi-common</module>
<module>ruoyi-demo</module>
<module>ruoyi-extend</module>
<module>ruoyi-oss</module>
<module>ruoyi-sms</module>
<module>ruoyi-cai</module>

View File

@@ -94,7 +94,6 @@
<!-- <artifactId>apm-toolkit-trace</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
</dependencies>
<build>

View File

@@ -22,5 +22,14 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-framework</artifactId>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-system</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,105 @@
package com.ruoyi.cai.auth;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.StpUtil;
import com.ruoyi.cai.domain.CaiUser;
import com.ruoyi.cai.domain.CaiUserInfo;
import com.ruoyi.cai.executor.ExecutorConstant;
import com.ruoyi.cai.service.CaiUserInfoService;
import com.ruoyi.cai.service.CaiUserService;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.UserType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ip.AddressUtils;
import com.ruoyi.system.service.SysLoginService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Collections;
@Component
@Slf4j
public class CaiLoginManager {
@Autowired
private CaiUserService caiUserService;
@Autowired
private SysLoginService sysLoginService;
public String login(String username,String password){
CaiUser caiUser = caiUserService.getByUsername(username);
if(caiUser == null){
throw new ServiceException("用户不存在或密码错误");
}
if(caiUser.getStatus() != 0){
throw new ServiceException("用户已封禁,请联系客服");
}
/*if(!BCrypt.checkpw(password, caiUser.getPassword())){
throw new ServiceException("用户不存在或密码错误");
}*/
LoginUser loginUser = new LoginUser();
loginUser.setDeptId(null);
loginUser.setDeptName(null);
// loginUser.setToken(caiUser.getToken());
// loginUser.setLoginTime();
// loginUser.setExpireTime();
// loginUser.setIpaddr();
// loginUser.setLoginLocation();
// loginUser.setBrowser();
// loginUser.setOs();
loginUser.setMenuPermission(Collections.emptySet());
loginUser.setRolePermission(Collections.emptySet());
loginUser.setUsername(caiUser.getMobile());
loginUser.setRoles(Collections.emptyList());
loginUser.setRoleId(null);
loginUser.setUserId(caiUser.getId());
loginUser.setUserType(UserType.APP_USER.getUserType());
LoginHelper.login(loginUser);
sysLoginService.recordLogininfor(loginUser.getUsername(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
String clientIP = ServletUtils.getClientIP();
ExecutorConstant.COMMON_EXECUTOR.execute(() -> recordLoginInfo(caiUser,clientIP));
return StpUtil.getTokenValue();
}
@Autowired
private CaiUserInfoService caiUserInfoService;
public void recordLoginInfo(CaiUser caiUser,String ip) {
String address = AddressUtils.getRealAddressByIP(ip);
CaiUserInfo caiUserInfo = caiUserInfoService.getById(caiUser.getId());
CaiUserInfo update = new CaiUserInfo();
update.setUserId(caiUser.getId());
update.setLoginCount(caiUserInfo.getLoginCount()+1);
update.setPrevLoginTime(caiUserInfo.getLastLoginTime());
update.setLastLoginIp(ip);
update.setLastLoginTime(LocalDateTime.now());
update.setLastLocation(address);
caiUserInfoService.updateById(update);
}
/**
* 退出登录
*/
public void logout() {
try {
LoginUser loginUser = LoginHelper.getLoginUser();
sysLoginService.recordLogininfor(loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
} catch (NotLoginException ignored) {
} finally {
try {
StpUtil.logout();
} catch (NotLoginException ignored) {
}
}
}
}

View File

@@ -0,0 +1,9 @@
package com.ruoyi.cai.auth;
import lombok.Data;
@Data
public class LoginCaiUser {
private String username;
private String password;
}

View File

@@ -0,0 +1,42 @@
package com.ruoyi.cai.controller.app;
import cn.dev33.satoken.annotation.SaIgnore;
import com.ruoyi.cai.auth.CaiLoginManager;
import com.ruoyi.cai.auth.LoginCaiUser;
import com.ruoyi.cai.service.CaiUserService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.model.LoginBody;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/cai/auth")
@SaIgnore
public class CaiAppAuthController {
@Autowired
private CaiLoginManager caiLoginManager;
@Autowired
private CaiUserService caiUserService;
@PostMapping("/register")
public R<Void> register(@RequestBody LoginCaiUser caiUser){
caiUserService.register(caiUser);
return R.ok();
}
@PostMapping("/login")
public R<Map<String,Object>> login(@RequestBody LoginBody loginBody){
Map<String, Object> ajax = new HashMap<>();
String token = caiLoginManager.login(loginBody.getUsername(), loginBody.getPassword());
ajax.put("token",token);
return R.ok(ajax);
}
}

View File

@@ -0,0 +1,19 @@
package com.ruoyi.cai.controller.app;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.helper.LoginHelper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/cai/user")
public class CaiAppUserController {
@GetMapping("/info")
public R<LoginUser> info(String user){
LoginUser loginUser = LoginHelper.getLoginUser();
return R.ok(loginUser);
}
}

View File

@@ -28,7 +28,7 @@ public class CaiUser implements Serializable {
*
*/
@TableId(value = "id")
private Integer id;
private Long id;
/**
* 用户号/ID号
*/

View File

@@ -0,0 +1,92 @@
package com.ruoyi.cai.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import java.math.BigDecimal;
import java.math.BigDecimal;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* 用户信息对象 cai_user_info
*
* @author ruoyi
* @date 2023-12-20
*/
@Data
@TableName("cai_user_info")
public class CaiUserInfo {
private static final long serialVersionUID=1L;
/**
*
*/
@TableId(value = "user_id",type = IdType.INPUT)
private Long userId;
/**
*
*/
private String realname;
/**
* 星座
*/
private Integer signs;
/**
* 用户评分
*/
private BigDecimal giveScore;
/**
* 奖励好友支出的比率
*/
private BigDecimal rewardPayRate;
/**
* 奖励好友收入的比率
*/
private BigDecimal rewardIncomeRate;
/**
* 奖励好友充值的比率
*/
private BigDecimal rewardRechargeRate;
/**
* 登录次数
*/
private Integer loginCount;
/**
* 连续登录天数
*/
private Long continueLoginCount;
/**
* 最大连续登录天数
*/
private Long maxLoginCount;
/**
* 上次登录时间
*/
private LocalDateTime prevLoginTime;
/**
* 最后登录IP
*/
private String lastLoginIp;
/**
* 最后登录时间
*/
private LocalDateTime lastLoginTime;
/**
* 最后登录位置
*/
private String lastLocation;
/**
* 注册IP
*/
private String regIp;
/**
* 注册时间
*/
private LocalDateTime regTime;
}

View File

@@ -0,0 +1,50 @@
package com.ruoyi.cai.executor;
import com.alibaba.ttl.threadpool.TtlExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.*;
/**
* 线程变量定义
* <p>created on 2023/3/3 11:16</p>
* @author ZL
*/
public class ExecutorConstant {
private final static int CPU_NUM = Runtime.getRuntime().availableProcessors();
public static Executor SYNC_EXECUTOR;
public static Executor COMMON_EXECUTOR;
static {
ThreadPoolExecutor syncExecutor = initExecutor(CPU_NUM,
CPU_NUM << 2,
5,
TimeUnit.SECONDS,
new SynchronousQueue<>(),
"syncThreadPool-%d");
SYNC_EXECUTOR = TtlExecutors.getTtlExecutor(syncExecutor);
ThreadPoolExecutor commonExecutor = new ThreadPoolExecutor(CPU_NUM,
CPU_NUM << 2,
5,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(50),
init("commonThreadPool-%d"),
new ThreadPoolExecutor.CallerRunsPolicy());
COMMON_EXECUTOR = TtlExecutors.getTtlExecutor(commonExecutor);
}
private static ThreadFactory init(String nameFormat){
return new ThreadFactoryBuilder().setNameFormat(nameFormat).build();
}
private static ThreadPoolExecutor initExecutor(int corePoolSize, int maxPoolSize, int keepAliveTime, TimeUnit timeUnit,
BlockingQueue<Runnable> workQueue, String nameFormat){
return new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, timeUnit, workQueue,
init(nameFormat));
}
}

View File

@@ -0,0 +1,7 @@
package com.ruoyi.cai.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.cai.domain.CaiUserInfo;
public interface CaiUserInfoMapper extends BaseMapper<CaiUserInfo> {
}

View File

@@ -0,0 +1,7 @@
package com.ruoyi.cai.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.cai.domain.CaiUserInfo;
public interface CaiUserInfoService extends IService<CaiUserInfo> {
}

View File

@@ -1,6 +1,7 @@
package com.ruoyi.cai.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.cai.auth.LoginCaiUser;
import com.ruoyi.cai.domain.CaiUser;
/**
@@ -11,4 +12,7 @@ import com.ruoyi.cai.domain.CaiUser;
*/
public interface CaiUserService extends IService<CaiUser> {
CaiUser getByUsername(String username);
void register(LoginCaiUser caiUser);
}

View File

@@ -0,0 +1,12 @@
package com.ruoyi.cai.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.cai.domain.CaiUserInfo;
import com.ruoyi.cai.mapper.CaiUserInfoMapper;
import com.ruoyi.cai.service.CaiUserInfoService;
import org.springframework.stereotype.Service;
@Service
public class CaiUserInfoServiceImpl extends ServiceImpl<CaiUserInfoMapper, CaiUserInfo> implements CaiUserInfoService {
}

View File

@@ -1,11 +1,11 @@
package com.ruoyi.cai.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.cai.domain.CaiUser;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.ruoyi.cai.mapper.CaiUserMapper;
import com.ruoyi.cai.service.CaiUserService;
import org.springframework.stereotype.Service;
/**
* 用户Service业务层处理
@@ -13,10 +13,12 @@ import com.ruoyi.cai.service.CaiUserService;
* @author 77
* @date 2023-12-19
*/
@RequiredArgsConstructor
@Service
public class CaiUserServiceImpl extends ServiceImpl<CaiUserMapper, CaiUser> implements CaiUserService {
private final CaiUserMapper baseMapper;
@Override
public CaiUser getByUsername(String username) {
return this.getOne(Wrappers.lambdaQuery(CaiUser.class)
.eq(CaiUser::getMobile,username));
}
}

View File

@@ -0,0 +1,21 @@
package com.ruoyi.common.core.domain.model;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
public class LoginBaseUser implements Serializable {
private Long userId;
private String userType;
public String getLoginId() {
if (userId == null) {
throw new IllegalArgumentException("用户ID不能为空");
}
return getUserType() + ":" + userId;
}
}

View File

@@ -1,33 +0,0 @@
<?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>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.8.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-demo</artifactId>
<description>
demo模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-sms</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,52 +0,0 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.email.MailUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
/**
* 邮件发送案例
*
* @author Michelle.Chung
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/mail")
public class MailController {
/**
* 发送邮件
*
* @param to 接收人
* @param subject 标题
* @param text 内容
*/
@GetMapping("/sendSimpleMessage")
public R<Void> sendSimpleMessage(String to, String subject, String text) {
MailUtils.sendText(to, subject, text);
return R.ok();
}
/**
* 发送邮件(带附件)
*
* @param to 接收人
* @param subject 标题
* @param text 内容
* @param filePath 附件路径
*/
@GetMapping("/sendMessageWithAttachment")
public R<Void> sendMessageWithAttachment(String to, String subject, String text, String filePath) {
MailUtils.sendText(to, subject, text, new File(filePath));
return R.ok();
}
}

View File

@@ -1,95 +0,0 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.constant.CacheNames;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.redis.RedisUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
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;
/**
* spring-cache 演示案例
*
* @author Lion Li
*/
// 类级别 缓存统一配置
//@CacheConfig(cacheNames = CacheNames.DEMO_CACHE)
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/cache")
public class RedisCacheController {
/**
* 测试 @Cacheable
* <p>
* 表示这个方法有了缓存的功能,方法的返回值会被缓存下来
* 下一次调用该方法前,会去检查是否缓存中已经有值
* 如果有就直接返回,不调用方法
* 如果没有,就调用方法,然后把结果缓存起来
* 这个注解「一般用在查询方法上」
* <p>
* 重点说明: 缓存注解严禁与其他筛选数据功能一起使用
* 例如: 数据权限注解 会造成 缓存击穿 与 数据不一致问题
* <p>
* cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数
*/
@Cacheable(cacheNames = "demo:cache#60s#10m#20", key = "#key", condition = "#key != null")
@GetMapping("/test1")
public R<String> test1(String key, String value) {
return R.ok("操作成功", value);
}
/**
* 测试 @CachePut
* <p>
* 加了@CachePut注解的方法,会把方法的返回值put到缓存里面缓存起来,供其它地方使用
* 它「通常用在新增或者实时更新方法上」
* <p>
* cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数
*/
@CachePut(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null")
@GetMapping("/test2")
public R<String> test2(String key, String value) {
return R.ok("操作成功", value);
}
/**
* 测试 @CacheEvict
* <p>
* 使用了CacheEvict注解的方法,会清空指定缓存
* 「一般用在删除的方法上」
* <p>
* cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数
*/
@CacheEvict(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null")
@GetMapping("/test3")
public R<String> test3(String key, String value) {
return R.ok("操作成功", value);
}
/**
* 测试设置过期时间
* 手动设置过期时间10秒
* 11秒后获取 判断是否相等
*/
@GetMapping("/test6")
public R<Boolean> test6(String key, String value) {
RedisUtils.setCacheObject(key, value);
boolean flag = RedisUtils.expire(key, Duration.ofSeconds(10));
System.out.println("***********" + flag);
try {
Thread.sleep(11 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object obj = RedisUtils.getCacheObject(key);
return R.ok(value.equals(obj));
}
}

View File

@@ -1,71 +0,0 @@
package com.ruoyi.demo.controller;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.lock.executor.RedissonLockExecutor;
import com.ruoyi.common.core.domain.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalTime;
/**
* 测试分布式锁的样例
*
* @author shenxinquan
*/
@Slf4j
@RestController
@RequestMapping("/demo/redisLock")
public class RedisLockController {
@Autowired
private LockTemplate lockTemplate;
/**
* 测试lock4j 注解
*/
@Lock4j(keys = {"#key"})
@GetMapping("/testLock4j")
public R<String> testLock4j(String key, String value) {
System.out.println("start:" + key + ",time:" + LocalTime.now().toString());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end :" + key + ",time:" + LocalTime.now().toString());
return R.ok("操作成功", value);
}
/**
* 测试lock4j 工具
*/
@GetMapping("/testLock4jLockTemplate")
public R<String> testLock4jLockTemplate(String key, String value) {
final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class);
if (null == lockInfo) {
throw new RuntimeException("业务处理中,请稍后再试");
}
// 获取锁成功,处理业务
try {
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
//
}
System.out.println("执行简单方法1 , 当前线程:" + Thread.currentThread().getName());
} finally {
//释放锁
lockTemplate.releaseLock(lockInfo);
}
//结束
return R.ok("操作成功", value);
}
}

View File

@@ -1,47 +0,0 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.redis.RedisUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Redis 发布订阅 演示案例
*
* @author Lion Li
*/
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/redis/pubsub")
public class RedisPubSubController {
/**
* 发布消息
*
* @param key 通道Key
* @param value 发送内容
*/
@GetMapping("/pub")
public R<Void> pub(String key, String value) {
RedisUtils.publish(key, value, consumer -> {
System.out.println("发布通道 => " + key + ", 发送值 => " + value);
});
return R.ok("操作成功");
}
/**
* 订阅消息
*
* @param key 通道Key
*/
@GetMapping("/sub")
public R<Void> sub(String key) {
RedisUtils.subscribe(key, String.class, msg -> {
System.out.println("订阅通道 => " + key + ", 接收值 => " + msg);
});
return R.ok("操作成功");
}
}

View File

@@ -1,64 +0,0 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.annotation.RateLimiter;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.enums.LimitType;
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;
/**
* 测试分布式限流样例
*
* @author Lion Li
*/
@Slf4j
@RestController
@RequestMapping("/demo/rateLimiter")
public class RedisRateLimiterController {
/**
* 测试全局限流
* 全局影响
*/
@RateLimiter(count = 2, time = 10)
@GetMapping("/test")
public R<String> test(String value) {
return R.ok("操作成功", value);
}
/**
* 测试请求IP限流
* 同一IP请求受影响
*/
@RateLimiter(count = 2, time = 10, limitType = LimitType.IP)
@GetMapping("/testip")
public R<String> testip(String value) {
return R.ok("操作成功", value);
}
/**
* 测试集群实例限流
* 启动两个后端服务互不影响
*/
@RateLimiter(count = 2, time = 10, limitType = LimitType.CLUSTER)
@GetMapping("/testcluster")
public R<String> testcluster(String value) {
return R.ok("操作成功", value);
}
/**
* 测试请求IP限流(key基于参数获取)
* 同一IP请求受影响
*
* 简单变量获取 #变量 复杂表达式 #{#变量 != 1 ? 1 : 0}
*/
@RateLimiter(count = 2, time = 10, limitType = LimitType.IP, key = "#value")
@GetMapping("/testObj")
public R<String> testObj(String value) {
return R.ok("操作成功", value);
}
}

View File

@@ -1,60 +0,0 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.R;
import lombok.RequiredArgsConstructor;
import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.core.factory.SmsFactory;
import org.dromara.sms4j.provider.enumerate.SupplierType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.LinkedHashMap;
/**
* 短信演示案例
* 请先阅读文档 否则无法使用
*
* @author Lion Li
* @version 4.2.0
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/sms")
public class SmsController {
/**
* 发送短信Aliyun
*
* @param phones 电话号
* @param templateId 模板ID
*/
@GetMapping("/sendAliyun")
public R<Object> sendAliyun(String phones, String templateId) {
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put("code", "1234");
SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map);
return R.ok(smsResponse);
}
/**
* 发送短信Tencent
*
* @param phones 电话号
* @param templateId 模板ID
*/
@GetMapping("/sendTencent")
public R<Object> sendTencent(String phones, String templateId) {
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
// map.put("2", "测试测试");
map.put("1", "1234");
SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.TENCENT);
SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map);
return R.ok(smsResponse);
}
}

View File

@@ -1,31 +0,0 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.R;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* swagger3 用法示例
*
* @author Lion Li
*/
@RestController
@RequestMapping("/swagger/demo")
public class Swagger3DemoController {
/**
* 上传请求
* 必须使用 @RequestPart 注解标注为文件
*
* @param file 文件
*/
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<String> upload(@RequestPart("file") MultipartFile file) {
return R.ok("操作成功", file.getOriginalFilename());
}
}

View File

@@ -1,90 +0,0 @@
package com.ruoyi.demo.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.mapper.TestDemoMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
* 测试批量方法
*
* @author Lion Li
* @date 2021-05-30
*/
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/batch")
public class TestBatchController extends BaseController {
/**
* 为了便于测试 直接引入mapper
*/
private final TestDemoMapper testDemoMapper;
/**
* 新增批量方法 可完美替代 saveBatch 秒级插入上万数据 (对mysql负荷较大)
* <p>
* 3.5.0 版本 增加 rewriteBatchedStatements=true 批处理参数 使 MP 原生批处理可以达到同样的速度
*/
@PostMapping("/add")
// @DS("slave")
public R<Void> add() {
List<TestDemo> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
TestDemo testDemo = new TestDemo();
testDemo.setOrderNum(-1);
testDemo.setTestKey("批量新增");
testDemo.setValue("测试新增");
list.add(testDemo);
}
return toAjax(testDemoMapper.insertBatch(list));
}
/**
* 新增或更新 可完美替代 saveOrUpdateBatch 高性能
* <p>
* 3.5.0 版本 增加 rewriteBatchedStatements=true 批处理参数 使 MP 原生批处理可以达到同样的速度
*/
@PostMapping("/addOrUpdate")
// @DS("slave")
public R<Void> addOrUpdate() {
List<TestDemo> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
TestDemo testDemo = new TestDemo();
testDemo.setOrderNum(-1);
testDemo.setTestKey("批量新增");
testDemo.setValue("测试新增");
list.add(testDemo);
}
testDemoMapper.insertBatch(list);
for (int i = 0; i < list.size(); i++) {
TestDemo testDemo = list.get(i);
testDemo.setTestKey("批量新增或修改");
testDemo.setValue("批量新增或修改");
if (i % 2 == 0) {
testDemo.setId(null);
}
}
return toAjax(testDemoMapper.insertOrUpdateBatch(list));
}
/**
* 删除批量方法
*/
@DeleteMapping()
// @DS("slave")
public R<Void> remove() {
return toAjax(testDemoMapper.delete(new LambdaQueryWrapper<TestDemo>()
.eq(TestDemo::getOrderNum, -1L)));
}
}

View File

@@ -1,148 +0,0 @@
package com.ruoyi.demo.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.excel.ExcelResult;
import com.ruoyi.common.utils.ValidatorUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.domain.bo.TestDemoBo;
import com.ruoyi.demo.domain.bo.TestDemoImportVo;
import com.ruoyi.demo.domain.vo.TestDemoVo;
import com.ruoyi.demo.service.ITestDemoService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 测试单表Controller
*
* @author Lion Li
* @date 2021-07-26
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/demo")
public class TestDemoController extends BaseController {
private final ITestDemoService iTestDemoService;
/**
* 查询测试单表列表
*/
@SaCheckPermission("demo:demo:list")
@GetMapping("/list")
public TableDataInfo<TestDemoVo> list(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) {
return iTestDemoService.queryPageList(bo, pageQuery);
}
/**
* 自定义分页查询
*/
@SaCheckPermission("demo:demo:list")
@GetMapping("/page")
public TableDataInfo<TestDemoVo> page(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) {
return iTestDemoService.customPageList(bo, pageQuery);
}
/**
* 导入数据
*
* @param file 导入文件
*/
@Log(title = "测试单表", businessType = BusinessType.IMPORT)
@SaCheckPermission("demo:demo:import")
@PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<Void> importData(@RequestPart("file") MultipartFile file) throws Exception {
ExcelResult<TestDemoImportVo> excelResult = ExcelUtil.importExcel(file.getInputStream(), TestDemoImportVo.class, true);
List<TestDemoImportVo> volist = excelResult.getList();
List<TestDemo> list = BeanUtil.copyToList(volist, TestDemo.class);
iTestDemoService.saveBatch(list);
return R.ok(excelResult.getAnalysis());
}
/**
* 导出测试单表列表
*/
@SaCheckPermission("demo:demo:export")
@Log(title = "测试单表", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(@Validated TestDemoBo bo, HttpServletResponse response) {
List<TestDemoVo> list = iTestDemoService.queryList(bo);
// 测试雪花id导出
// for (TestDemoVo vo : list) {
// vo.setId(1234567891234567893L);
// }
ExcelUtil.exportExcel(list, "测试单表", TestDemoVo.class, response);
}
/**
* 获取测试单表详细信息
*
* @param id 测试ID
*/
@SaCheckPermission("demo:demo:query")
@GetMapping("/{id}")
public R<TestDemoVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable("id") Long id) {
return R.ok(iTestDemoService.queryById(id));
}
/**
* 新增测试单表
*/
@SaCheckPermission("demo:demo:add")
@Log(title = "测试单表", businessType = BusinessType.INSERT)
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "{repeat.submit.message}")
@PostMapping()
public R<Void> add(@RequestBody TestDemoBo bo) {
// 使用校验工具对标 @Validated(AddGroup.class) 注解
// 用于在非 Controller 的地方校验对象
ValidatorUtils.validate(bo, AddGroup.class);
return toAjax(iTestDemoService.insertByBo(bo));
}
/**
* 修改测试单表
*/
@SaCheckPermission("demo:demo:edit")
@Log(title = "测试单表", businessType = BusinessType.UPDATE)
@RepeatSubmit
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody TestDemoBo bo) {
return toAjax(iTestDemoService.updateByBo(bo));
}
/**
* 删除测试单表
*
* @param ids 测试ID串
*/
@SaCheckPermission("demo:demo:remove")
@Log(title = "测试单表", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(iTestDemoService.deleteWithValidByIds(Arrays.asList(ids), true));
}
}

View File

@@ -1,55 +0,0 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.demo.domain.TestDemoEncrypt;
import com.ruoyi.demo.mapper.TestDemoEncryptMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* 测试数据库加解密功能
*
* @author Lion Li
*/
@Validated
@RestController
@RequestMapping("/demo/encrypt")
public class TestEncryptController {
@Autowired
private TestDemoEncryptMapper mapper;
@Value("${mybatis-encryptor.enable}")
private Boolean encryptEnable;
/**
* 测试数据库加解密
*
* @param key 测试key
* @param value 测试value
*/
@GetMapping()
public R<Map<String, TestDemoEncrypt>> test(String key, String value) {
if (!encryptEnable) {
throw new RuntimeException("加密功能未开启!");
}
Map<String, TestDemoEncrypt> map = new HashMap<>(2);
TestDemoEncrypt demo = new TestDemoEncrypt();
demo.setTestKey(key);
demo.setValue(value);
mapper.insert(demo);
map.put("加密", demo);
TestDemoEncrypt testDemo = mapper.selectById(demo.getId());
map.put("解密", testDemo);
return R.ok(map);
}
}

View File

@@ -1,125 +0,0 @@
package com.ruoyi.demo.controller;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.excel.ExcelResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.demo.domain.vo.ExportDemoVo;
import com.ruoyi.demo.listener.ExportDemoListener;
import com.ruoyi.demo.service.IExportExcelService;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 测试Excel功能
*
* @author Lion Li
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/demo/excel")
public class TestExcelController {
private final IExportExcelService exportExcelService;
/**
* 单列表多数据
*/
@GetMapping("/exportTemplateOne")
public void exportTemplateOne(HttpServletResponse response) {
Map<String, String> map = new HashMap<>();
map.put("title", "单列表多数据");
map.put("test1", "数据测试1");
map.put("test2", "数据测试2");
map.put("test3", "数据测试3");
map.put("test4", "数据测试4");
map.put("testTest", "666");
List<TestObj> list = new ArrayList<>();
list.add(new TestObj("单列表测试1", "列表测试1", "列表测试2", "列表测试3", "列表测试4"));
list.add(new TestObj("单列表测试2", "列表测试5", "列表测试6", "列表测试7", "列表测试8"));
list.add(new TestObj("单列表测试3", "列表测试9", "列表测试10", "列表测试11", "列表测试12"));
ExcelUtil.exportTemplate(CollUtil.newArrayList(map, list), "单列表.xlsx", "excel/单列表.xlsx", response);
}
/**
* 多列表多数据
*/
@GetMapping("/exportTemplateMuliti")
public void exportTemplateMuliti(HttpServletResponse response) {
Map<String, String> map = new HashMap<>();
map.put("title1", "标题1");
map.put("title2", "标题2");
map.put("title3", "标题3");
map.put("title4", "标题4");
map.put("author", "Lion Li");
List<TestObj1> list1 = new ArrayList<>();
list1.add(new TestObj1("list1测试1", "list1测试2", "list1测试3"));
list1.add(new TestObj1("list1测试4", "list1测试5", "list1测试6"));
list1.add(new TestObj1("list1测试7", "list1测试8", "list1测试9"));
List<TestObj1> list2 = new ArrayList<>();
list2.add(new TestObj1("list2测试1", "list2测试2", "list2测试3"));
list2.add(new TestObj1("list2测试4", "list2测试5", "list2测试6"));
List<TestObj1> list3 = new ArrayList<>();
list3.add(new TestObj1("list3测试1", "list3测试2", "list3测试3"));
List<TestObj1> list4 = new ArrayList<>();
list4.add(new TestObj1("list4测试1", "list4测试2", "list4测试3"));
list4.add(new TestObj1("list4测试4", "list4测试5", "list4测试6"));
list4.add(new TestObj1("list4测试7", "list4测试8", "list4测试9"));
list4.add(new TestObj1("list4测试10", "list4测试11", "list4测试12"));
Map<String, Object> multiListMap = new HashMap<>();
multiListMap.put("map", map);
multiListMap.put("data1", list1);
multiListMap.put("data2", list2);
multiListMap.put("data3", list3);
multiListMap.put("data4", list4);
ExcelUtil.exportTemplateMultiList(multiListMap, "多列表.xlsx", "excel/多列表.xlsx", response);
}
/**
* 导出下拉框
*
* @param response /
*/
@GetMapping("/exportWithOptions")
public void exportWithOptions(HttpServletResponse response) {
exportExcelService.exportWithOptions(response);
}
/**
* 导入表格
*/
@PostMapping(value = "/importWithOptions", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public List<ExportDemoVo> importWithOptions(@RequestPart("file") MultipartFile file) throws Exception {
// 处理解析结果
ExcelResult<ExportDemoVo> excelResult = ExcelUtil.importExcel(file.getInputStream(), ExportDemoVo.class, new ExportDemoListener());
return excelResult.getList();
}
@Data
@AllArgsConstructor
static class TestObj1 {
private String test1;
private String test2;
private String test3;
}
@Data
@AllArgsConstructor
static class TestObj {
private String name;
private String list1;
private String list2;
private String list3;
private String list4;
}
}

View File

@@ -1,71 +0,0 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.MessageUtils;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 测试国际化
*
* @author Lion Li
*/
@Validated
@RestController
@RequestMapping("/demo/i18n")
public class TestI18nController {
/**
* 通过code获取国际化内容
* code为 messages.properties 中的 key
* <p>
* 测试使用 user.register.success
*
* @param code 国际化code
*/
@GetMapping()
public R<Void> get(String code) {
return R.ok(MessageUtils.message(code));
}
/**
* Validator 校验国际化
* 不传值 分别查看异常返回
* <p>
* 测试使用 not.null
*/
@GetMapping("/test1")
public R<Void> test1(@NotBlank(message = "{not.null}") String str) {
return R.ok(str);
}
/**
* Bean 校验国际化
* 不传值 分别查看异常返回
* <p>
* 测试使用 not.null
*/
@GetMapping("/test2")
public R<TestI18nBo> test2(@Validated TestI18nBo bo) {
return R.ok(bo);
}
@Data
public static class TestI18nBo {
@NotBlank(message = "{not.null}")
private String name;
@NotNull(message = "{not.null}")
@Range(min = 0, max = 100, message = "{length.not.valid}")
private Integer age;
}
}

View File

@@ -1,75 +0,0 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.annotation.Sensitive;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.enums.SensitiveStrategy;
import lombok.Data;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 测试数据脱敏控制器
* <p>
* 默认管理员不过滤
* 需自行根据业务重写实现
*
* @author Lion Li
* @version 3.6.0
* @see com.ruoyi.common.core.service.SensitiveService
*/
@RestController
@RequestMapping("/demo/sensitive")
public class TestSensitiveController extends BaseController {
/**
* 测试数据脱敏
*/
@GetMapping("/test")
public R<TestSensitive> test() {
TestSensitive testSensitive = new TestSensitive();
testSensitive.setIdCard("210397198608215431");
testSensitive.setPhone("17640125371");
testSensitive.setAddress("北京市朝阳区某某四合院1203室");
testSensitive.setEmail("17640125371@163.com");
testSensitive.setBankCard("6226456952351452853");
return R.ok(testSensitive);
}
@Data
static class TestSensitive {
/**
* 身份证
*/
@Sensitive(strategy = SensitiveStrategy.ID_CARD)
private String idCard;
/**
* 电话
*/
@Sensitive(strategy = SensitiveStrategy.PHONE)
private String phone;
/**
* 地址
*/
@Sensitive(strategy = SensitiveStrategy.ADDRESS)
private String address;
/**
* 邮箱
*/
@Sensitive(strategy = SensitiveStrategy.EMAIL)
private String email;
/**
* 银行卡
*/
@Sensitive(strategy = SensitiveStrategy.BANK_CARD)
private String bankCard;
}
}

View File

@@ -1,107 +0,0 @@
package com.ruoyi.demo.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.demo.domain.bo.TestTreeBo;
import com.ruoyi.demo.domain.vo.TestTreeVo;
import com.ruoyi.demo.service.ITestTreeService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
/**
* 测试树表Controller
*
* @author Lion Li
* @date 2021-07-26
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/tree")
public class TestTreeController extends BaseController {
private final ITestTreeService iTestTreeService;
/**
* 查询测试树表列表
*/
@SaCheckPermission("demo:tree:list")
@GetMapping("/list")
public R<List<TestTreeVo>> list(@Validated(QueryGroup.class) TestTreeBo bo) {
List<TestTreeVo> list = iTestTreeService.queryList(bo);
return R.ok(list);
}
/**
* 导出测试树表列表
*/
@SaCheckPermission("demo:tree:export")
@Log(title = "测试树表", businessType = BusinessType.EXPORT)
@GetMapping("/export")
public void export(@Validated TestTreeBo bo, HttpServletResponse response) {
List<TestTreeVo> list = iTestTreeService.queryList(bo);
ExcelUtil.exportExcel(list, "测试树表", TestTreeVo.class, response);
}
/**
* 获取测试树表详细信息
*
* @param id 测试树ID
*/
@SaCheckPermission("demo:tree:query")
@GetMapping("/{id}")
public R<TestTreeVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable("id") Long id) {
return R.ok(iTestTreeService.queryById(id));
}
/**
* 新增测试树表
*/
@SaCheckPermission("demo:tree:add")
@Log(title = "测试树表", businessType = BusinessType.INSERT)
@RepeatSubmit
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody TestTreeBo bo) {
return toAjax(iTestTreeService.insertByBo(bo));
}
/**
* 修改测试树表
*/
@SaCheckPermission("demo:tree:edit")
@Log(title = "测试树表", businessType = BusinessType.UPDATE)
@RepeatSubmit
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody TestTreeBo bo) {
return toAjax(iTestTreeService.updateByBo(bo));
}
/**
* 删除测试树表
*
* @param ids 测试树ID串
*/
@SaCheckPermission("demo:tree:remove")
@Log(title = "测试树表", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(iTestTreeService.deleteWithValidByIds(Arrays.asList(ids), true));
}
}

View File

@@ -1 +0,0 @@
package com.ruoyi.demo.controller;

View File

@@ -1,90 +0,0 @@
package com.ruoyi.demo.controller.queue;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.redis.QueueUtils;
import lombok.RequiredArgsConstructor;
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;
/**
* 有界队列 演示案例
* <p>
* 轻量级队列 重量级数据量 请使用 MQ
* <p>
* 集群测试通过 同一个数据只会被消费一次 做好事务补偿
* 集群测试流程 在其中一台发送数据 两端分别调用获取接口 一次获取一条
*
* @author Lion Li
* @version 3.6.0
*/
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/queue/bounded")
public class BoundedQueueController {
/**
* 添加队列数据
*
* @param queueName 队列名
* @param capacity 容量
*/
@GetMapping("/add")
public R<Void> add(String queueName, int capacity) {
// 用完了一定要销毁 否则会一直存在
boolean b = QueueUtils.destroyBoundedQueue(queueName);
log.info("通道: {} , 删除: {}", queueName, b);
// 初始化设置一次即可
if (QueueUtils.trySetBoundedQueueCapacity(queueName, capacity)) {
log.info("通道: {} , 设置容量: {}", queueName, capacity);
} else {
log.info("通道: {} , 设置容量失败", queueName);
return R.fail("操作失败");
}
for (int i = 0; i < 11; i++) {
String data = "data-" + i;
boolean flag = QueueUtils.addBoundedQueueObject(queueName, data);
if (flag == false) {
log.info("通道: {} , 发送数据: {} 失败, 通道已满", queueName, data);
} else {
log.info("通道: {} , 发送数据: {}", queueName, data);
}
}
return R.ok("操作成功");
}
/**
* 删除队列数据
*
* @param queueName 队列名
*/
@GetMapping("/remove")
public R<Void> remove(String queueName) {
String data = "data-" + 5;
if (QueueUtils.removeBoundedQueueObject(queueName, data)) {
log.info("通道: {} , 删除数据: {}", queueName, data);
} else {
return R.fail("操作失败");
}
return R.ok("操作成功");
}
/**
* 获取队列数据
*
* @param queueName 队列名
*/
@GetMapping("/get")
public R<Void> get(String queueName) {
String data;
do {
data = QueueUtils.getBoundedQueueObject(queueName);
log.info("通道: {} , 获取数据: {}", queueName, data);
} while (data != null);
return R.ok("操作成功");
}
}

View File

@@ -1,90 +0,0 @@
package com.ruoyi.demo.controller.queue;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.redis.QueueUtils;
import lombok.RequiredArgsConstructor;
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.util.concurrent.TimeUnit;
/**
* 延迟队列 演示案例
* <p>
* 轻量级队列 重量级数据量 请使用 MQ
* 例如: 创建订单30分钟后过期处理
* <p>
* 集群测试通过 同一个数据只会被消费一次 做好事务补偿
* 集群测试流程 两台集群分别开启订阅 在其中一台发送数据 观察接收消息的规律
*
* @author Lion Li
* @version 3.6.0
*/
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/queue/delayed")
public class DelayedQueueController {
/**
* 订阅队列
*
* @param queueName 队列名
*/
@GetMapping("/subscribe")
public R<Void> subscribe(String queueName) {
log.info("通道: {} 监听中......", queueName);
// 项目初始化设置一次即可
QueueUtils.subscribeBlockingQueue(queueName, (String orderNum) -> {
// 观察接收时间
log.info("通道: {}, 收到数据: {}", queueName, orderNum);
}, true);
return R.ok("操作成功");
}
/**
* 添加队列数据
*
* @param queueName 队列名
* @param orderNum 订单号
* @param time 延迟时间(秒)
*/
@GetMapping("/add")
public R<Void> add(String queueName, String orderNum, Long time) {
QueueUtils.addDelayedQueueObject(queueName, orderNum, time, TimeUnit.SECONDS);
// 观察发送时间
log.info("通道: {} , 发送数据: {}", queueName, orderNum);
return R.ok("操作成功");
}
/**
* 删除队列数据
*
* @param queueName 队列名
* @param orderNum 订单号
*/
@GetMapping("/remove")
public R<Void> remove(String queueName, String orderNum) {
if (QueueUtils.removeDelayedQueueObject(queueName, orderNum)) {
log.info("通道: {} , 删除数据: {}", queueName, orderNum);
} else {
return R.fail("操作失败");
}
return R.ok("操作成功");
}
/**
* 销毁队列
*
* @param queueName 队列名
*/
@GetMapping("/destroy")
public R<Void> destroy(String queueName) {
// 用完了一定要销毁 否则会一直存在
QueueUtils.destroyDelayedQueue(queueName);
return R.ok("操作成功");
}
}

View File

@@ -1,22 +0,0 @@
package com.ruoyi.demo.controller.queue;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 实体类 注意不允许使用内部类 否则会找不到类
*
* @author Lion Li
* @version 3.6.0
*/
@Data
@NoArgsConstructor
public class PriorityDemo implements Comparable<PriorityDemo> {
private String name;
private Integer orderNum;
@Override
public int compareTo(PriorityDemo other) {
return Integer.compare(getOrderNum(), other.getOrderNum());
}
}

View File

@@ -1,89 +0,0 @@
package com.ruoyi.demo.controller.queue;
import cn.hutool.core.util.RandomUtil;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.redis.QueueUtils;
import lombok.RequiredArgsConstructor;
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;
/**
* 优先队列 演示案例
* <p>
* 轻量级队列 重量级数据量 请使用 MQ
* <p>
* 集群测试通过 同一个消息只会被消费一次 做好事务补偿
* 集群测试流程 在其中一台发送数据 两端分别调用获取接口 一次获取一条
*
* @author Lion Li
* @version 3.6.0
*/
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/queue/priority")
public class PriorityQueueController {
/**
* 添加队列数据
*
* @param queueName 队列名
*/
@GetMapping("/add")
public R<Void> add(String queueName) {
// 用完了一定要销毁 否则会一直存在
boolean b = QueueUtils.destroyPriorityQueue(queueName);
log.info("通道: {} , 删除: {}", queueName, b);
for (int i = 0; i < 10; i++) {
int randomNum = RandomUtil.randomInt(10);
PriorityDemo data = new PriorityDemo();
data.setName("data-" + i);
data.setOrderNum(randomNum);
if (QueueUtils.addPriorityQueueObject(queueName, data)) {
log.info("通道: {} , 发送数据: {}", queueName, data);
} else {
log.info("通道: {} , 发送数据: {}, 发送失败", queueName, data);
}
}
return R.ok("操作成功");
}
/**
* 删除队列数据
*
* @param queueName 队列名
* @param name 对象名
* @param orderNum 排序号
*/
@GetMapping("/remove")
public R<Void> remove(String queueName, String name, Integer orderNum) {
PriorityDemo data = new PriorityDemo();
data.setName(name);
data.setOrderNum(orderNum);
if (QueueUtils.removePriorityQueueObject(queueName, data)) {
log.info("通道: {} , 删除数据: {}", queueName, data);
} else {
return R.fail("操作失败");
}
return R.ok("操作成功");
}
/**
* 获取队列数据
*
* @param queueName 队列名
*/
@GetMapping("/get")
public R<Void> get(String queueName) {
PriorityDemo data;
do {
data = QueueUtils.getPriorityQueueObject(queueName);
log.info("通道: {} , 获取数据: {}", queueName, data);
} while (data != null);
return R.ok("操作成功");
}
}

View File

@@ -1,66 +0,0 @@
package com.ruoyi.demo.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 测试单表对象 test_demo
*
* @author Lion Li
* @date 2021-07-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("test_demo")
public class TestDemo extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 部门id
*/
private Long deptId;
/**
* 用户id
*/
private Long userId;
/**
* 排序号
*/
@OrderBy(asc = false, sort = 1)
private Integer orderNum;
/**
* key键
*/
private String testKey;
/**
* 值
*/
private String value;
/**
* 版本
*/
@Version
private Long version;
/**
* 删除标志
*/
@TableLogic
private Long delFlag;
}

View File

@@ -1,29 +0,0 @@
package com.ruoyi.demo.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.EncryptField;
import com.ruoyi.common.enums.AlgorithmType;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("test_demo")
public class TestDemoEncrypt extends TestDemo {
/**
* key键
*/
// @EncryptField(algorithm=AlgorithmType.SM2, privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgZSlOvw8FBiH+aFJWLYZP/VRjg9wjfRarTkGBZd/T3N+gCgYIKoEcz1UBgi2hRANCAAR5DGuQwJqkxnbCsP+iPSDoHWIF4RwcR5EsSvT8QPxO1wRkR2IhCkzvRb32x2CUgJFdvoqVqfApFDPZzShqzBwX", publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEeQxrkMCapMZ2wrD/oj0g6B1iBeEcHEeRLEr0/ED8TtcEZEdiIQpM70W99sdglICRXb6KlanwKRQz2c0oaswcFw==")
@EncryptField(algorithm = AlgorithmType.RSA, privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANBBEeueWlXlkkj2+WY5l+IWe42d8b5K28g+G/CFKC/yYAEHtqGlCsBOrb+YBkG9mPzmuYA/n9k0NFIc8E8yY5vZQaroyFBrTTWEzG9RY2f7Y3svVyybs6jpXSUs4xff8abo7wL1Y/wUaeatTViamxYnyTvdTmLm3d+JjRij68rxAgMBAAECgYAB0TnhXraSopwIVRfmboea1b0upl+BUdTJcmci412UjrKr5aE695ZLPkXbFXijVu7HJlyyv94NVUdaMACV7Ku/S2RuNB70M7YJm8rAjHFC3/i2ZeIM60h1Ziy4QKv0XM3pRATlDCDNhC1WUrtQCQSgU8kcp6eUUppruOqDzcY04QJBAPm9+sBP9CwDRgy3e5+V8aZtJkwDstb0lVVV/KY890cydVxiCwvX3fqVnxKMlb+x0YtH0sb9v+71xvK2lGobaRECQQDVePU6r/cCEfpc+nkWF6osAH1f8Mux3rYv2DoBGvaPzV2BGfsLed4neRfCwWNCKvGPCdW+L0xMJg8+RwaoBUPhAkAT5kViqXxFPYWJYd1h2+rDXhMdH3ZSlm6HvDBDdrwlWinr0Iwcx3iSjPV93uHXwm118aUj4fg3LDJMCKxOwBxhAkByrQXfvwOMYygBprRBf/j0plazoWFrbd6lGR0f1uI5IfNnFRPdeFw1DEINZ2Hw+6zEUF44SqRMC+4IYJNc02dBAkBCgy7RvfyV/A7N6kKXxTHauY0v6XwSSvpeKtRJkbIcRWOdIYvaHO9L7cklj3vIEdwjSUp9K4VTBYYlmAz1xh03", publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQQRHrnlpV5ZJI9vlmOZfiFnuNnfG+StvIPhvwhSgv8mABB7ahpQrATq2/mAZBvZj85rmAP5/ZNDRSHPBPMmOb2UGq6MhQa001hMxvUWNn+2N7L1csm7Oo6V0lLOMX3/Gm6O8C9WP8FGnmrU1YmpsWJ8k73U5i5t3fiY0Yo+vK8QIDAQAB")
private String testKey;
/**
* 值
*/
// @EncryptField // 什么也不写走默认yml配置
// @EncryptField(algorithm = AlgorithmType.SM4, password = "10rfylhtccpuyke5")
@EncryptField(algorithm = AlgorithmType.AES, password = "10rfylhtccpuyke5")
private String value;
}

View File

@@ -1,58 +0,0 @@
package com.ruoyi.demo.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.Version;
import com.ruoyi.common.core.domain.TreeEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 测试树表对象 test_tree
*
* @author Lion Li
* @date 2021-07-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("test_tree")
public class TestTree extends TreeEntity<TestTree> {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 部门id
*/
private Long deptId;
/**
* 用户id
*/
private Long userId;
/**
* 树节点名
*/
private String treeName;
/**
* 版本
*/
@Version
private Long version;
/**
* 删除标志
*/
@TableLogic
private Long delFlag;
}

View File

@@ -1,59 +0,0 @@
package com.ruoyi.demo.domain.bo;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 测试单表业务对象 test_demo
*
* @author Lion Li
* @date 2021-07-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TestDemoBo extends BaseEntity {
/**
* 主键
*/
@NotNull(message = "主键不能为空", groups = {EditGroup.class})
private Long id;
/**
* 部门id
*/
@NotNull(message = "部门id不能为空", groups = {AddGroup.class, EditGroup.class})
private Long deptId;
/**
* 用户id
*/
@NotNull(message = "用户id不能为空", groups = {AddGroup.class, EditGroup.class})
private Long userId;
/**
* 排序号
*/
@NotNull(message = "排序号不能为空", groups = {AddGroup.class, EditGroup.class})
private Integer orderNum;
/**
* key键
*/
@NotBlank(message = "key键不能为空", groups = {AddGroup.class, EditGroup.class})
private String testKey;
/**
* 值
*/
@NotBlank(message = "值不能为空", groups = {AddGroup.class, EditGroup.class})
private String value;
}

View File

@@ -1,53 +0,0 @@
package com.ruoyi.demo.domain.bo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 测试单表业务对象 test_demo
*
* @author Lion Li
* @date 2021-07-26
*/
@Data
public class TestDemoImportVo {
/**
* 部门id
*/
@NotNull(message = "部门id不能为空")
@ExcelProperty(value = "部门id")
private Long deptId;
/**
* 用户id
*/
@NotNull(message = "用户id不能为空")
@ExcelProperty(value = "用户id")
private Long userId;
/**
* 排序号
*/
@NotNull(message = "排序号不能为空")
@ExcelProperty(value = "排序号")
private Long orderNum;
/**
* key键
*/
@NotBlank(message = "key键不能为空")
@ExcelProperty(value = "key键")
private String testKey;
/**
* 值
*/
@NotBlank(message = "值不能为空")
@ExcelProperty(value = "")
private String value;
}

View File

@@ -1,47 +0,0 @@
package com.ruoyi.demo.domain.bo;
import com.ruoyi.common.core.domain.TreeEntity;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 测试树表业务对象 test_tree
*
* @author Lion Li
* @date 2021-07-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TestTreeBo extends TreeEntity<TestTreeBo> {
/**
* 主键
*/
@NotNull(message = "主键不能为空", groups = {EditGroup.class})
private Long id;
/**
* 部门id
*/
@NotNull(message = "部门id不能为空", groups = {AddGroup.class, EditGroup.class})
private Long deptId;
/**
* 用户id
*/
@NotNull(message = "用户id不能为空", groups = {AddGroup.class, EditGroup.class})
private Long userId;
/**
* 树节点名
*/
@NotBlank(message = "树节点名不能为空", groups = {AddGroup.class, EditGroup.class})
private String treeName;
}

View File

@@ -1 +0,0 @@
package com.ruoyi.demo.domain;

View File

@@ -1,119 +0,0 @@
package com.ruoyi.demo.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.annotation.ExcelEnumFormat;
import com.ruoyi.common.convert.ExcelDictConvert;
import com.ruoyi.common.convert.ExcelEnumConvert;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.enums.UserStatus;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 带有下拉选的Excel导出
*
* @author Emil.Zhang
*/
@Data
@ExcelIgnoreUnannotated
@AllArgsConstructor
@NoArgsConstructor
public class ExportDemoVo {
private static final long serialVersionUID = 1L;
/**
* 用户昵称
*/
@ExcelProperty(value = "用户名", index = 0)
@NotEmpty(message = "用户名不能为空", groups = AddGroup.class)
private String nickName;
/**
* 用户类型
* </p>
* 使用ExcelEnumFormat注解需要进行下拉选的部分
*/
@ExcelProperty(value = "用户类型", index = 1, converter = ExcelEnumConvert.class)
@ExcelEnumFormat(enumClass = UserStatus.class, textField = "info")
@NotEmpty(message = "用户类型不能为空", groups = AddGroup.class)
private String userStatus;
/**
* 性别
* <p>
* 使用ExcelDictFormat注解需要进行下拉选的部分
*/
@ExcelProperty(value = "性别", index = 2, converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_user_sex")
@NotEmpty(message = "性别不能为空", groups = AddGroup.class)
private String gender;
/**
* 手机号
*/
@ExcelProperty(value = "手机号", index = 3)
@NotEmpty(message = "手机号不能为空", groups = AddGroup.class)
private String phoneNumber;
/**
* Email
*/
@ExcelProperty(value = "Email", index = 4)
@NotEmpty(message = "Email不能为空", groups = AddGroup.class)
private String email;
/**
* 省
* <p>
* 级联下拉,仅判断是否选了
*/
@ExcelProperty(value = "", index = 5)
@NotNull(message = "省不能为空", groups = AddGroup.class)
private String province;
/**
* 数据库中的省ID
* </p>
* 处理完毕后再判断是否市正确的值
*/
@NotNull(message = "请勿手动输入", groups = EditGroup.class)
private Integer provinceId;
/**
* 市
* <p>
* 级联下拉
*/
@ExcelProperty(value = "", index = 6)
@NotNull(message = "市不能为空", groups = AddGroup.class)
private String city;
/**
* 数据库中的市ID
*/
@NotNull(message = "请勿手动输入", groups = EditGroup.class)
private Integer cityId;
/**
* 县
* <p>
* 级联下拉
*/
@ExcelProperty(value = "", index = 7)
@NotNull(message = "县不能为空", groups = AddGroup.class)
private String area;
/**
* 数据库中的县ID
*/
@NotNull(message = "请勿手动输入", groups = EditGroup.class)
private Integer areaId;
}

View File

@@ -1,83 +0,0 @@
package com.ruoyi.demo.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.util.Date;
/**
* 测试单表视图对象 test_demo
*
* @author Lion Li
* @date 2021-07-26
*/
@Data
@ExcelIgnoreUnannotated
public class TestDemoVo {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ExcelProperty(value = "主键")
private Long id;
/**
* 部门id
*/
@ExcelProperty(value = "部门id")
private Long deptId;
/**
* 用户id
*/
@ExcelProperty(value = "用户id")
private Long userId;
/**
* 排序号
*/
@ExcelProperty(value = "排序号")
private Integer orderNum;
/**
* key键
*/
@ExcelProperty(value = "key键")
private String testKey;
/**
* 值
*/
@ExcelProperty(value = "")
private String value;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
private Date createTime;
/**
* 创建人
*/
@ExcelProperty(value = "创建人")
private String createBy;
/**
* 更新时间
*/
@ExcelProperty(value = "更新时间")
private Date updateTime;
/**
* 更新人
*/
@ExcelProperty(value = "更新人")
private String updateBy;
}

View File

@@ -1,58 +0,0 @@
package com.ruoyi.demo.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.util.Date;
/**
* 测试树表视图对象 test_tree
*
* @author Lion Li
* @date 2021-07-26
*/
@Data
@ExcelIgnoreUnannotated
public class TestTreeVo {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 父id
*/
@ExcelProperty(value = "父id")
private Long parentId;
/**
* 部门id
*/
@ExcelProperty(value = "部门id")
private Long deptId;
/**
* 用户id
*/
@ExcelProperty(value = "用户id")
private Long userId;
/**
* 树节点名
*/
@ExcelProperty(value = "树节点名")
private String treeName;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
private Date createTime;
}

View File

@@ -1,68 +0,0 @@
package com.ruoyi.demo.listener;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.excel.DefaultExcelListener;
import com.ruoyi.common.excel.DropDownOptions;
import com.ruoyi.common.utils.ValidatorUtils;
import com.ruoyi.demo.domain.vo.ExportDemoVo;
import java.util.List;
/**
* Excel带下拉框的解析处理器
*
* @author Emil.Zhang
*/
public class ExportDemoListener extends DefaultExcelListener<ExportDemoVo> {
public ExportDemoListener() {
// 显示使用构造函数,否则将导致空指针
super(true);
}
@Override
public void invoke(ExportDemoVo data, AnalysisContext context) {
// 先校验必填
ValidatorUtils.validate(data, AddGroup.class);
// 处理级联下拉的部分
String province = data.getProvince();
String city = data.getCity();
String area = data.getArea();
// 本行用户选择的省
List<String> thisRowSelectedProvinceOption = DropDownOptions.analyzeOptionValue(province);
if (thisRowSelectedProvinceOption.size() == 2) {
String provinceIdStr = thisRowSelectedProvinceOption.get(1);
if (NumberUtil.isNumber(provinceIdStr)) {
// 严格要求数据的话可以在这里做与数据库相关的判断
// 例如判断省信息是否在数据库中存在等建议结合RedisCache做缓存10s减少数据库调用
data.setProvinceId(Integer.parseInt(provinceIdStr));
}
}
// 本行用户选择的市
List<String> thisRowSelectedCityOption = DropDownOptions.analyzeOptionValue(city);
if (thisRowSelectedCityOption.size() == 2) {
String cityIdStr = thisRowSelectedCityOption.get(1);
if (NumberUtil.isNumber(cityIdStr)) {
data.setCityId(Integer.parseInt(cityIdStr));
}
}
// 本行用户选择的县
List<String> thisRowSelectedAreaOption = DropDownOptions.analyzeOptionValue(area);
if (thisRowSelectedAreaOption.size() == 2) {
String areaIdStr = thisRowSelectedAreaOption.get(1);
if (NumberUtil.isNumber(areaIdStr)) {
data.setAreaId(Integer.parseInt(areaIdStr));
}
}
// 处理完毕以后判断是否符合规则
ValidatorUtils.validate(data, EditGroup.class);
// 添加到处理结果中
getExcelResult().getList().add(data);
}
}

View File

@@ -1,13 +0,0 @@
package com.ruoyi.demo.mapper;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
import com.ruoyi.demo.domain.TestDemoEncrypt;
/**
* 测试加密功能
*
* @author Lion Li
*/
public interface TestDemoEncryptMapper extends BaseMapperPlus<TestDemoEncryptMapper, TestDemoEncrypt, TestDemoEncrypt> {
}

View File

@@ -1,58 +0,0 @@
package com.ruoyi.demo.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.domain.vo.TestDemoVo;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List;
/**
* 测试单表Mapper接口
*
* @author Lion Li
* @date 2021-07-26
*/
public interface TestDemoMapper extends BaseMapperPlus<TestDemoMapper, TestDemo, TestDemoVo> {
@DataPermission({
@DataColumn(key = "deptName", value = "dept_id"),
@DataColumn(key = "userName", value = "user_id")
})
Page<TestDemoVo> customPageList(@Param("page") Page<TestDemo> page, @Param("ew") Wrapper<TestDemo> wrapper);
@Override
@DataPermission({
@DataColumn(key = "deptName", value = "dept_id"),
@DataColumn(key = "userName", value = "user_id")
})
List<TestDemo> selectList(IPage<TestDemo> page, @Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
@Override
@DataPermission({
@DataColumn(key = "deptName", value = "dept_id"),
@DataColumn(key = "userName", value = "user_id")
})
List<TestDemo> selectList(@Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
@Override
@DataPermission({
@DataColumn(key = "deptName", value = "dept_id"),
@DataColumn(key = "userName", value = "user_id")
})
int updateById(@Param(Constants.ENTITY) TestDemo entity);
@Override
@DataPermission({
@DataColumn(key = "deptName", value = "dept_id"),
@DataColumn(key = "userName", value = "user_id")
})
int deleteBatchIds(@Param(Constants.COLL) Collection<?> idList);
}

View File

@@ -1,21 +0,0 @@
package com.ruoyi.demo.mapper;
import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
import com.ruoyi.demo.domain.TestTree;
import com.ruoyi.demo.domain.vo.TestTreeVo;
/**
* 测试树表Mapper接口
*
* @author Lion Li
* @date 2021-07-26
*/
@DataPermission({
@DataColumn(key = "deptName", value = "dept_id"),
@DataColumn(key = "userName", value = "user_id")
})
public interface TestTreeMapper extends BaseMapperPlus<TestTreeMapper, TestTree, TestTreeVo> {
}

View File

@@ -1 +0,0 @@
package com.ruoyi.demo.mapper;

View File

@@ -1,18 +0,0 @@
package com.ruoyi.demo.service;
import javax.servlet.http.HttpServletResponse;
/**
* 导出下拉框Excel示例
*
* @author Emil.Zhang
*/
public interface IExportExcelService {
/**
* 导出下拉框
*
* @param response /
*/
void exportWithOptions(HttpServletResponse response);
}

View File

@@ -1,71 +0,0 @@
package com.ruoyi.demo.service;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.domain.bo.TestDemoBo;
import com.ruoyi.demo.domain.vo.TestDemoVo;
import java.util.Collection;
import java.util.List;
/**
* 测试单表Service接口
*
* @author Lion Li
* @date 2021-07-26
*/
public interface ITestDemoService {
/**
* 查询单个
*
* @return
*/
TestDemoVo queryById(Long id);
/**
* 查询列表
*/
TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery);
/**
* 自定义分页查询
*/
TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo, PageQuery pageQuery);
/**
* 查询列表
*/
List<TestDemoVo> queryList(TestDemoBo bo);
/**
* 根据新增业务对象插入测试单表
*
* @param bo 测试单表新增业务对象
* @return
*/
Boolean insertByBo(TestDemoBo bo);
/**
* 根据编辑业务对象修改测试单表
*
* @param bo 测试单表编辑业务对象
* @return
*/
Boolean updateByBo(TestDemoBo bo);
/**
* 校验并删除数据
*
* @param ids 主键集合
* @param isValid 是否校验,true-删除前校验,false-不校验
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 批量保存
*/
Boolean saveBatch(List<TestDemo> list);
}

View File

@@ -1,52 +0,0 @@
package com.ruoyi.demo.service;
import com.ruoyi.demo.domain.bo.TestTreeBo;
import com.ruoyi.demo.domain.vo.TestTreeVo;
import java.util.Collection;
import java.util.List;
/**
* 测试树表Service接口
*
* @author Lion Li
* @date 2021-07-26
*/
public interface ITestTreeService {
/**
* 查询单个
*
* @return
*/
TestTreeVo queryById(Long id);
/**
* 查询列表
*/
List<TestTreeVo> queryList(TestTreeBo bo);
/**
* 根据新增业务对象插入测试树表
*
* @param bo 测试树表新增业务对象
* @return
*/
Boolean insertByBo(TestTreeBo bo);
/**
* 根据编辑业务对象修改测试树表
*
* @param bo 测试树表编辑业务对象
* @return
*/
Boolean updateByBo(TestTreeBo bo);
/**
* 校验并删除数据
*
* @param ids 主键集合
* @param isValid 是否校验,true-删除前校验,false-不校验
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -1,223 +0,0 @@
package com.ruoyi.demo.service.impl;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.excel.DropDownOptions;
import com.ruoyi.common.utils.StreamUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.demo.domain.vo.ExportDemoVo;
import com.ruoyi.demo.service.IExportExcelService;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 导出下拉框Excel示例
*
* @author Emil.Zhang
*/
@Service
@RequiredArgsConstructor
public class ExportExcelServiceImpl implements IExportExcelService {
@Override
public void exportWithOptions(HttpServletResponse response) {
// 创建表格数据,业务中一般通过数据库查询
List<ExportDemoVo> excelDataList = new ArrayList<>();
for (int i = 0; i < 3; i++) {
// 模拟数据库中的一条数据
ExportDemoVo everyRowData = new ExportDemoVo();
everyRowData.setNickName("用户-" + i);
everyRowData.setUserStatus(UserStatus.OK.getCode());
everyRowData.setGender("1");
everyRowData.setPhoneNumber(String.format("175%08d", i));
everyRowData.setEmail(String.format("175%08d", i) + "@163.com");
everyRowData.setProvinceId(i);
everyRowData.setCityId(i);
everyRowData.setAreaId(i);
excelDataList.add(everyRowData);
}
// 通过@ExcelIgnoreUnannotated配合@ExcelProperty合理显示需要的列
// 并通过@DropDown注解指定下拉值或者通过创建ExcelOptions来指定下拉框
// 使用ExcelOptions时建议指定列index防止出现下拉列解析不对齐
// 首先从数据库中查询下拉框内的可选项
// 这里模拟查询结果
List<DemoCityData> provinceList = getProvinceList(),
cityList = getCityList(provinceList),
areaList = getAreaList(cityList);
int provinceIndex = 5, cityIndex = 6, areaIndex = 7;
DropDownOptions provinceToCity = DropDownOptions.buildLinkedOptions(
provinceList,
provinceIndex,
cityList,
cityIndex,
DemoCityData::getId,
DemoCityData::getPid,
everyOptions -> DropDownOptions.createOptionValue(
everyOptions.getName(),
everyOptions.getId()
)
);
DropDownOptions cityToArea = DropDownOptions.buildLinkedOptions(
cityList,
cityIndex,
areaList,
areaIndex,
DemoCityData::getId,
DemoCityData::getPid,
everyOptions -> DropDownOptions.createOptionValue(
everyOptions.getName(),
everyOptions.getId()
)
);
// 把所有的下拉框存储
List<DropDownOptions> options = new ArrayList<>();
options.add(provinceToCity);
options.add(cityToArea);
// 到此为止所有的下拉框可选项已全部配置完毕
// 接下来需要将Excel中的展示数据转换为对应的下拉选
List<ExportDemoVo> outList = StreamUtils.toList(excelDataList, everyRowData -> {
// 只需要处理没有使用@ExcelDictFormat注解的下拉框
// 一般来说,可以直接在数据库查询即查询出省市县信息,这里通过模拟操作赋值
everyRowData.setProvince(buildOptions(provinceList, everyRowData.getProvinceId()));
everyRowData.setCity(buildOptions(cityList, everyRowData.getCityId()));
everyRowData.setArea(buildOptions(areaList, everyRowData.getAreaId()));
return everyRowData;
});
ExcelUtil.exportExcel(outList, "下拉框示例", ExportDemoVo.class, response, options);
}
private String buildOptions(List<DemoCityData> cityDataList, Integer id) {
Map<Integer, List<DemoCityData>> groupByIdMap =
cityDataList.stream().collect(Collectors.groupingBy(DemoCityData::getId));
if (groupByIdMap.containsKey(id)) {
DemoCityData demoCityData = groupByIdMap.get(id).get(0);
return DropDownOptions.createOptionValue(demoCityData.getName(), demoCityData.getId());
} else {
return StrUtil.EMPTY;
}
}
/**
* 模拟查询数据库操作
*
* @return /
*/
private List<DemoCityData> getProvinceList() {
List<DemoCityData> provinceList = new ArrayList<>();
// 实际业务中一般采用数据库读取的形式,这里直接拼接创建
provinceList.add(new DemoCityData(0, null, "安徽省"));
provinceList.add(new DemoCityData(1, null, "江苏省"));
return provinceList;
}
/**
* 模拟查找数据库操作,需要连带查询出省的数据
*
* @param provinceList 模拟的父省数据
* @return /
*/
private List<DemoCityData> getCityList(List<DemoCityData> provinceList) {
List<DemoCityData> cityList = new ArrayList<>();
// 实际业务中一般采用数据库读取的形式,这里直接拼接创建
cityList.add(new DemoCityData(0, 0, "合肥市"));
cityList.add(new DemoCityData(1, 0, "芜湖市"));
cityList.add(new DemoCityData(2, 1, "南京市"));
cityList.add(new DemoCityData(3, 1, "无锡市"));
cityList.add(new DemoCityData(4, 1, "徐州市"));
selectParentData(provinceList, cityList);
return cityList;
}
/**
* 模拟查找数据库操作,需要连带查询出市的数据
*
* @param cityList 模拟的父市数据
* @return /
*/
private List<DemoCityData> getAreaList(List<DemoCityData> cityList) {
List<DemoCityData> areaList = new ArrayList<>();
// 实际业务中一般采用数据库读取的形式,这里直接拼接创建
areaList.add(new DemoCityData(0, 0, "瑶海区"));
areaList.add(new DemoCityData(1, 0, "庐江区"));
areaList.add(new DemoCityData(2, 1, "南宁县"));
areaList.add(new DemoCityData(3, 1, "镜湖区"));
areaList.add(new DemoCityData(4, 2, "玄武区"));
areaList.add(new DemoCityData(5, 2, "秦淮区"));
areaList.add(new DemoCityData(6, 3, "宜兴市"));
areaList.add(new DemoCityData(7, 3, "新吴区"));
areaList.add(new DemoCityData(8, 4, "鼓楼区"));
areaList.add(new DemoCityData(9, 4, "丰县"));
selectParentData(cityList, areaList);
return areaList;
}
/**
* 模拟数据库的查询父数据操作
*
* @param parentList /
* @param sonList /
*/
private void selectParentData(List<DemoCityData> parentList, List<DemoCityData> sonList) {
Map<Integer, List<DemoCityData>> parentGroupByIdMap =
parentList.stream().collect(Collectors.groupingBy(DemoCityData::getId));
sonList.forEach(everySon -> {
if (parentGroupByIdMap.containsKey(everySon.getPid())) {
everySon.setPData(parentGroupByIdMap.get(everySon.getPid()).get(0));
}
});
}
/**
* 模拟的数据库省市县
*/
@Data
private static class DemoCityData {
/**
* 数据库id字段
*/
private Integer id;
/**
* 数据库pid字段
*/
private Integer pid;
/**
* 数据库name字段
*/
private String name;
/**
* MyBatisPlus连带查询父数据
*/
private DemoCityData pData;
public DemoCityData(Integer id, Integer pid, String name) {
this.id = id;
this.pid = pid;
this.name = name;
}
}
}

View File

@@ -1,110 +0,0 @@
package com.ruoyi.demo.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.domain.bo.TestDemoBo;
import com.ruoyi.demo.domain.vo.TestDemoVo;
import com.ruoyi.demo.mapper.TestDemoMapper;
import com.ruoyi.demo.service.ITestDemoService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 测试单表Service业务层处理
*
* @author Lion Li
* @date 2021-07-26
*/
@RequiredArgsConstructor
@Service
public class TestDemoServiceImpl implements ITestDemoService {
private final TestDemoMapper baseMapper;
@Override
public TestDemoVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
@Override
public TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo);
Page<TestDemoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 自定义分页查询
*/
@Override
public TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo);
Page<TestDemoVo> result = baseMapper.customPageList(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
@Override
public List<TestDemoVo> queryList(TestDemoBo bo) {
return baseMapper.selectVoList(buildQueryWrapper(bo));
}
private LambdaQueryWrapper<TestDemo> buildQueryWrapper(TestDemoBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<TestDemo> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey());
lqw.eq(StringUtils.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue());
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
return lqw;
}
@Override
public Boolean insertByBo(TestDemoBo bo) {
TestDemo add = BeanUtil.toBean(bo, TestDemo.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
@Override
public Boolean updateByBo(TestDemoBo bo) {
TestDemo update = BeanUtil.toBean(bo, TestDemo.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*
* @param entity 实体类数据
*/
private void validEntityBeforeSave(TestDemo entity) {
//TODO 做一些数据校验,如唯一约束
}
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
public Boolean saveBatch(List<TestDemo> list) {
return baseMapper.insertBatch(list);
}
}

View File

@@ -1,87 +0,0 @@
package com.ruoyi.demo.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.demo.domain.TestTree;
import com.ruoyi.demo.domain.bo.TestTreeBo;
import com.ruoyi.demo.domain.vo.TestTreeVo;
import com.ruoyi.demo.mapper.TestTreeMapper;
import com.ruoyi.demo.service.ITestTreeService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 测试树表Service业务层处理
*
* @author Lion Li
* @date 2021-07-26
*/
// @DS("slave") // 切换从库查询
@RequiredArgsConstructor
@Service
public class TestTreeServiceImpl implements ITestTreeService {
private final TestTreeMapper baseMapper;
@Override
public TestTreeVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
// @DS("slave") // 切换从库查询
@Override
public List<TestTreeVo> queryList(TestTreeBo bo) {
LambdaQueryWrapper<TestTree> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<TestTree> buildQueryWrapper(TestTreeBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<TestTree> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName());
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
TestTree::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
return lqw;
}
@Override
public Boolean insertByBo(TestTreeBo bo) {
TestTree add = BeanUtil.toBean(bo, TestTree.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
@Override
public Boolean updateByBo(TestTreeBo bo) {
TestTree update = BeanUtil.toBean(bo, TestTree.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*
* @param entity 实体类数据
*/
private void validEntityBeforeSave(TestTree entity) {
//TODO 做一些数据校验,如唯一约束
}
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -1 +0,0 @@
package com.ruoyi.demo.service.impl;

View File

@@ -1 +0,0 @@
package com.ruoyi.demo.service;

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.demo.mapper.TestDemoMapper">
<resultMap type="com.ruoyi.demo.domain.TestDemo" id="TestDemoResult">
<result property="id" column="id"/>
<result property="deptId" column="dept_id"/>
<result property="userId" column="user_id"/>
<result property="orderNum" column="order_num"/>
<result property="testKey" column="test_key"/>
<result property="value" column="value"/>
<result property="version" column="version"/>
<result property="createTime" column="create_time"/>
<result property="createBy" column="create_by"/>
<result property="updateTime" column="update_time"/>
<result property="updateBy" column="update_by"/>
<result property="delFlag" column="del_flag"/>
</resultMap>
<select id="customPageList" resultType="com.ruoyi.demo.domain.vo.TestDemoVo">
SELECT * FROM test_demo ${ew.customSqlSegment}
</select>
</mapper>

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.demo.mapper.TestTreeMapper">
<resultMap type="com.ruoyi.demo.domain.TestTree" id="TestTreeResult">
<result property="id" column="id"/>
<result property="parentId" column="parent_id"/>
<result property="deptId" column="dept_id"/>
<result property="userId" column="user_id"/>
<result property="treeName" column="tree_name"/>
<result property="version" column="version"/>
<result property="createTime" column="create_time"/>
<result property="createBy" column="create_by"/>
<result property="updateTime" column="update_time"/>
<result property="updateBy" column="update_by"/>
<result property="delFlag" column="del_flag"/>
</resultMap>
</mapper>

View File

@@ -1,3 +0,0 @@
java包使用 `.` 分割 resource 目录使用 `/` 分割
<br>
此文件目的 防止文件夹粘连找不到 `xml` 文件

View File

@@ -1,19 +0,0 @@
<?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>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.8.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-extend</artifactId>
<packaging>pom</packaging>
<modules>
<module>ruoyi-monitor-admin</module>
<module>ruoyi-xxl-job-admin</module>
</modules>
</project>

View File

@@ -1,13 +0,0 @@
FROM anapsix/alpine-java:8_server-jre_unlimited
MAINTAINER Lion Li
RUN mkdir -p /ruoyi/monitor/logs
WORKDIR /ruoyi/monitor
EXPOSE 9090
ADD ./target/ruoyi-monitor-admin.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]

View File

@@ -1,65 +0,0 @@
<?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>ruoyi-extend</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.8.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>ruoyi-monitor-admin</artifactId>
<dependencies>
<!-- SpringWeb模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring security 安全认证 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<fork>true</fork> <!-- 如果没有该配置devtools不会生效 -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,19 +0,0 @@
package com.ruoyi.monitor.admin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Admin 监控启动程序
*
* @author Lion Li
*/
@SpringBootApplication
public class MonitorAdminApplication {
public static void main(String[] args) {
SpringApplication.run(MonitorAdminApplication.class, args);
System.out.println("Admin 监控启动成功");
}
}

View File

@@ -1,31 +0,0 @@
package com.ruoyi.monitor.admin.config;
import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
import org.springframework.boot.task.TaskExecutorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
/**
* springboot-admin server配置类
*
* @author Lion Li
*/
@Configuration
@EnableAdminServer
public class AdminServerConfig {
@Lazy
@Bean(name = TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)
@ConditionalOnMissingBean(Executor.class)
public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
return builder.build();
}
}

View File

@@ -1,50 +0,0 @@
package com.ruoyi.monitor.admin.config;
import de.codecentric.boot.admin.server.config.AdminServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
/**
* admin 监控 安全配置
*
* @author Lion Li
*/
@EnableWebSecurity
public class SecurityConfig {
private final String adminContextPath;
public SecurityConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(adminContextPath + "/");
return httpSecurity
.headers().frameOptions().disable()
.and().authorizeRequests()
.antMatchers(adminContextPath + "/assets/**"
, adminContextPath + "/login"
, "/actuator"
, "/actuator/**"
).permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage(adminContextPath + "/login")
.successHandler(successHandler).and()
.logout().logoutUrl(adminContextPath + "/logout")
.and()
.httpBasic().and()
.csrf()
.disable()
.build();
}
}

View File

@@ -1,40 +0,0 @@
package com.ruoyi.monitor.admin.notifier;
import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
import de.codecentric.boot.admin.server.notify.AbstractEventNotifier;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
/**
* 自定义事件通知处理
*
* @author Lion Li
*/
@Slf4j
@Component
public class CustomNotifier extends AbstractEventNotifier {
protected CustomNotifier(InstanceRepository repository) {
super(repository);
}
@Override
@SuppressWarnings("all")
protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
return Mono.fromRunnable(() -> {
// 实例状态改变事件
if (event instanceof InstanceStatusChangedEvent) {
String registName = instance.getRegistration().getName();
String instanceId = event.getInstance().getValue();
String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();
log.info("Instance Status Change: [{}],[{}],[{}]", registName, instanceId, status);
}
});
}
}

View File

@@ -1,45 +0,0 @@
server:
port: 9090
spring:
application:
name: ruoyi-monitor-admin
profiles:
active: @profiles.active@
logging:
config: classpath:logback-plus.xml
--- # 监控中心服务端配置
spring:
security:
user:
name: ruoyi
password: 123456
boot:
admin:
ui:
title: RuoYi-Vue-Plus服务监控中心
context-path: /admin
--- # Actuator 监控端点的配置项
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: ALWAYS
logfile:
external-file: ./logs/ruoyi-monitor-admin.log
--- # 监控配置
spring.boot.admin.client:
# 增加客户端开关
enabled: true
# 设置 Spring Boot Admin Server 地址
url: http://localhost:9090/admin
instance:
service-host-type: IP
username: ruoyi
password: 123456

View File

@@ -1,8 +0,0 @@
Application Version: ${ruoyi-vue-plus.version}
Spring Boot Version: ${spring-boot.version}
__ __ _ _ _ _
| \/ | (_) | /\ | | (_)
| \ / | ___ _ __ _| |_ ___ _ __ ______ / \ __| |_ __ ___ _ _ __
| |\/| |/ _ \| '_ \| | __/ _ \| '__|______/ /\ \ / _` | '_ ` _ \| | '_ \
| | | | (_) | | | | | || (_) | | / ____ \ (_| | | | | | | | | | |
|_| |_|\___/|_| |_|_|\__\___/|_| /_/ \_\__,_|_| |_| |_|_|_| |_|

View File

@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="1 seconds">
<contextName>logback</contextName>
<property name="log.path" value="./logs/ruoyi-monitor-admin"/>
<property name="console.log.pattern"
value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${console.log.pattern}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="file"/>
</root>
</configuration>

View File

@@ -1,16 +0,0 @@
FROM anapsix/alpine-java:8_server-jre_unlimited
MAINTAINER Lion Li
RUN mkdir -p /ruoyi/xxljob/logs
WORKDIR /ruoyi/xxljob
ENV TZ=PRC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
EXPOSE 9100
ADD ./target/ruoyi-xxl-job-admin.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]

View File

@@ -1,102 +0,0 @@
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>ruoyi-extend</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.8.2</version>
</parent>
<artifactId>ruoyi-xxl-job-admin</artifactId>
<packaging>jar</packaging>
<properties>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- starter-webspring-webmvc + autoconfigure + logback + yaml + tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- starter-testjunit + spring-test + mockito -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- freemarker-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- mail-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- starter-actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- mybatis-startermybatis + mybatis-spring + hikaridefault -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${spring-boot.mybatis}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<!-- xxl-job-core -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,16 +0,0 @@
package com.xxl.job.admin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author xuxueli 2018-10-28 00:38:13
*/
@SpringBootApplication
public class XxlJobAdminApplication {
public static void main(String[] args) {
SpringApplication.run(XxlJobAdminApplication.class, args);
}
}

View File

@@ -1,97 +0,0 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.service.LoginService;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
/**
* index controller
*
* @author xuxueli 2015-12-19 16:13:16
*/
@Controller
public class IndexController {
@Resource
private XxlJobService xxlJobService;
@Resource
private LoginService loginService;
@RequestMapping("/")
public String index(Model model) {
Map<String, Object> dashboardMap = xxlJobService.dashboardInfo();
model.addAllAttributes(dashboardMap);
return "index";
}
@RequestMapping("/chartInfo")
@ResponseBody
public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
ReturnT<Map<String, Object>> chartInfo = xxlJobService.chartInfo(startDate, endDate);
return chartInfo;
}
@RequestMapping("/toLogin")
@PermissionLimit(limit = false)
public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) {
if (loginService.ifLogin(request, response) != null) {
modelAndView.setView(new RedirectView("/", true, false));
return modelAndView;
}
return new ModelAndView("login");
}
@RequestMapping(value = "login", method = RequestMethod.POST)
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> loginDo(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember) {
boolean ifRem = (ifRemember != null && ifRemember.trim().length() > 0 && "on".equals(ifRemember)) ? true : false;
return loginService.login(request, response, userName, password, ifRem);
}
@RequestMapping(value = "logout", method = RequestMethod.POST)
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response) {
return loginService.logout(request, response);
}
@RequestMapping("/help")
public String help() {
/*if (!PermissionInterceptor.ifLogin(request)) {
return "redirect:/toLogin";
}*/
return "help";
}
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
}

View File

@@ -1,72 +0,0 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.RegistryParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.util.GsonTool;
import com.xxl.job.core.util.XxlJobRemotingUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* Created by xuxueli on 17/5/10.
*/
@Controller
@RequestMapping("/api")
public class JobApiController {
@Resource
private AdminBiz adminBiz;
/**
* api
*
* @param uri
* @param data
* @return
*/
@RequestMapping("/{uri}")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> api(HttpServletRequest request, @PathVariable("uri") String uri, @RequestBody(required = false) String data) {
// valid
if (!"POST".equalsIgnoreCase(request.getMethod())) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, HttpMethod not support.");
}
if (uri == null || uri.trim().length() == 0) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping empty.");
}
if (XxlJobAdminConfig.getAdminConfig().getAccessToken() != null
&& XxlJobAdminConfig.getAdminConfig().getAccessToken().trim().length() > 0
&& !XxlJobAdminConfig.getAdminConfig().getAccessToken().equals(request.getHeader(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN))) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "The access token is wrong.");
}
// services mapping
if ("callback".equals(uri)) {
List<HandleCallbackParam> callbackParamList = GsonTool.fromJson(data, List.class, HandleCallbackParam.class);
return adminBiz.callback(callbackParamList);
} else if ("registry".equals(uri)) {
RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
return adminBiz.registry(registryParam);
} else if ("registryRemove".equals(uri)) {
RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
return adminBiz.registryRemove(registryParam);
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping(" + uri + ") not found.");
}
}
}

View File

@@ -1,97 +0,0 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLogGlue;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogGlueDao;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.glue.GlueTypeEnum;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
/**
* job code controller
*
* @author xuxueli 2015-12-19 16:13:16
*/
@Controller
@RequestMapping("/jobcode")
public class JobCodeController {
@Resource
private XxlJobInfoDao xxlJobInfoDao;
@Resource
private XxlJobLogGlueDao xxlJobLogGlueDao;
@RequestMapping
public String index(HttpServletRequest request, Model model, int jobId) {
XxlJobInfo jobInfo = xxlJobInfoDao.loadById(jobId);
List<XxlJobLogGlue> jobLogGlues = xxlJobLogGlueDao.findByJobId(jobId);
if (jobInfo == null) {
throw new RuntimeException(I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
}
if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType())) {
throw new RuntimeException(I18nUtil.getString("jobinfo_glue_gluetype_unvalid"));
}
// valid permission
JobInfoController.validPermission(request, jobInfo.getJobGroup());
// Glue类型-字典
model.addAttribute("GlueTypeEnum", GlueTypeEnum.values());
model.addAttribute("jobInfo", jobInfo);
model.addAttribute("jobLogGlues", jobLogGlues);
return "jobcode/jobcode.index";
}
@RequestMapping("/save")
@ResponseBody
public ReturnT<String> save(Model model, int id, String glueSource, String glueRemark) {
// valid
if (glueRemark == null) {
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_remark")));
}
if (glueRemark.length() < 4 || glueRemark.length() > 100) {
return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_remark_limit"));
}
XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(id);
if (exists_jobInfo == null) {
return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
}
// update new code
exists_jobInfo.setGlueSource(glueSource);
exists_jobInfo.setGlueRemark(glueRemark);
exists_jobInfo.setGlueUpdatetime(new Date());
exists_jobInfo.setUpdateTime(new Date());
xxlJobInfoDao.update(exists_jobInfo);
// log old code
XxlJobLogGlue xxlJobLogGlue = new XxlJobLogGlue();
xxlJobLogGlue.setJobId(exists_jobInfo.getId());
xxlJobLogGlue.setGlueType(exists_jobInfo.getGlueType());
xxlJobLogGlue.setGlueSource(glueSource);
xxlJobLogGlue.setGlueRemark(glueRemark);
xxlJobLogGlue.setAddTime(new Date());
xxlJobLogGlue.setUpdateTime(new Date());
xxlJobLogGlueDao.save(xxlJobLogGlue);
// remove code backup more than 30
xxlJobLogGlueDao.removeOld(exists_jobInfo.getId(), 30);
return ReturnT.SUCCESS;
}
}

View File

@@ -1,205 +0,0 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobRegistry;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobRegistryDao;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.enums.RegistryConfig;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
* job group controller
*
* @author xuxueli 2016-10-02 20:52:56
*/
@Controller
@RequestMapping("/jobgroup")
public class JobGroupController {
@Resource
public XxlJobInfoDao xxlJobInfoDao;
@Resource
public XxlJobGroupDao xxlJobGroupDao;
@Resource
private XxlJobRegistryDao xxlJobRegistryDao;
@RequestMapping
@PermissionLimit(adminuser = true)
public String index(Model model) {
return "jobgroup/jobgroup.index";
}
@RequestMapping("/pageList")
@ResponseBody
@PermissionLimit(adminuser = true)
public Map<String, Object> pageList(HttpServletRequest request,
@RequestParam(required = false, defaultValue = "0") int start,
@RequestParam(required = false, defaultValue = "10") int length,
String appname, String title) {
// page query
List<XxlJobGroup> list = xxlJobGroupDao.pageList(start, length, appname, title);
int list_count = xxlJobGroupDao.pageListCount(start, length, appname, title);
// package result
Map<String, Object> maps = new HashMap<String, Object>();
maps.put("recordsTotal", list_count); // 总记录数
maps.put("recordsFiltered", list_count); // 过滤后的总记录数
maps.put("data", list); // 分页列表
return maps;
}
@RequestMapping("/save")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> save(XxlJobGroup xxlJobGroup) {
// valid
if (xxlJobGroup.getAppname() == null || xxlJobGroup.getAppname().trim().length() == 0) {
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + "AppName"));
}
if (xxlJobGroup.getAppname().length() < 4 || xxlJobGroup.getAppname().length() > 64) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appname_length"));
}
if (xxlJobGroup.getAppname().contains(">") || xxlJobGroup.getAppname().contains("<")) {
return new ReturnT<String>(500, "AppName" + I18nUtil.getString("system_unvalid"));
}
if (xxlJobGroup.getTitle() == null || xxlJobGroup.getTitle().trim().length() == 0) {
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")));
}
if (xxlJobGroup.getTitle().contains(">") || xxlJobGroup.getTitle().contains("<")) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_title") + I18nUtil.getString("system_unvalid"));
}
if (xxlJobGroup.getAddressType() != 0) {
if (xxlJobGroup.getAddressList() == null || xxlJobGroup.getAddressList().trim().length() == 0) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit"));
}
if (xxlJobGroup.getAddressList().contains(">") || xxlJobGroup.getAddressList().contains("<")) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList") + I18nUtil.getString("system_unvalid"));
}
String[] addresss = xxlJobGroup.getAddressList().split(",");
for (String item : addresss) {
if (item == null || item.trim().length() == 0) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList_unvalid"));
}
}
}
// process
xxlJobGroup.setUpdateTime(new Date());
int ret = xxlJobGroupDao.save(xxlJobGroup);
return (ret > 0) ? ReturnT.SUCCESS : ReturnT.FAIL;
}
@RequestMapping("/update")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> update(XxlJobGroup xxlJobGroup) {
// valid
if (xxlJobGroup.getAppname() == null || xxlJobGroup.getAppname().trim().length() == 0) {
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + "AppName"));
}
if (xxlJobGroup.getAppname().length() < 4 || xxlJobGroup.getAppname().length() > 64) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appname_length"));
}
if (xxlJobGroup.getTitle() == null || xxlJobGroup.getTitle().trim().length() == 0) {
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")));
}
if (xxlJobGroup.getAddressType() == 0) {
// 0=自动注册
List<String> registryList = findRegistryByAppName(xxlJobGroup.getAppname());
String addressListStr = null;
if (registryList != null && !registryList.isEmpty()) {
Collections.sort(registryList);
addressListStr = "";
for (String item : registryList) {
addressListStr += item + ",";
}
addressListStr = addressListStr.substring(0, addressListStr.length() - 1);
}
xxlJobGroup.setAddressList(addressListStr);
} else {
// 1=手动录入
if (xxlJobGroup.getAddressList() == null || xxlJobGroup.getAddressList().trim().length() == 0) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit"));
}
String[] addresss = xxlJobGroup.getAddressList().split(",");
for (String item : addresss) {
if (item == null || item.trim().length() == 0) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList_unvalid"));
}
}
}
// process
xxlJobGroup.setUpdateTime(new Date());
int ret = xxlJobGroupDao.update(xxlJobGroup);
return (ret > 0) ? ReturnT.SUCCESS : ReturnT.FAIL;
}
private List<String> findRegistryByAppName(String appnameParam) {
HashMap<String, List<String>> appAddressMap = new HashMap<String, List<String>>();
List<XxlJobRegistry> list = xxlJobRegistryDao.findAll(RegistryConfig.DEAD_TIMEOUT, new Date());
if (list != null) {
for (XxlJobRegistry item : list) {
if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) {
String appname = item.getRegistryKey();
List<String> registryList = appAddressMap.get(appname);
if (registryList == null) {
registryList = new ArrayList<String>();
}
if (!registryList.contains(item.getRegistryValue())) {
registryList.add(item.getRegistryValue());
}
appAddressMap.put(appname, registryList);
}
}
}
return appAddressMap.get(appnameParam);
}
@RequestMapping("/remove")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> remove(int id) {
// valid
int count = xxlJobInfoDao.pageListCount(0, 10, id, -1, null, null, null);
if (count > 0) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_del_limit_0"));
}
List<XxlJobGroup> allList = xxlJobGroupDao.findAll();
if (allList.size() == 1) {
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_del_limit_1"));
}
int ret = xxlJobGroupDao.remove(id);
return (ret > 0) ? ReturnT.SUCCESS : ReturnT.FAIL;
}
@RequestMapping("/loadById")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<XxlJobGroup> loadById(int id) {
XxlJobGroup jobGroup = xxlJobGroupDao.load(id);
return jobGroup != null ? new ReturnT<XxlJobGroup>(jobGroup) : new ReturnT<XxlJobGroup>(ReturnT.FAIL_CODE, null);
}
}

View File

@@ -1,180 +0,0 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.core.exception.XxlJobException;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum;
import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum;
import com.xxl.job.admin.core.thread.JobScheduleHelper;
import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.service.LoginService;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
import com.xxl.job.core.glue.GlueTypeEnum;
import com.xxl.job.core.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
* index controller
*
* @author xuxueli 2015-12-19 16:13:16
*/
@Controller
@RequestMapping("/jobinfo")
public class JobInfoController {
private static Logger logger = LoggerFactory.getLogger(JobInfoController.class);
@Resource
private XxlJobGroupDao xxlJobGroupDao;
@Resource
private XxlJobService xxlJobService;
@RequestMapping
public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "-1") int jobGroup) {
// 枚举-字典
model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values()); // 路由策略-列表
model.addAttribute("GlueTypeEnum", GlueTypeEnum.values()); // Glue类型-字典
model.addAttribute("ExecutorBlockStrategyEnum", ExecutorBlockStrategyEnum.values()); // 阻塞处理策略-字典
model.addAttribute("ScheduleTypeEnum", ScheduleTypeEnum.values()); // 调度类型
model.addAttribute("MisfireStrategyEnum", MisfireStrategyEnum.values()); // 调度过期策略
// 执行器列表
List<XxlJobGroup> jobGroupList_all = xxlJobGroupDao.findAll();
// filter group
List<XxlJobGroup> jobGroupList = filterJobGroupByRole(request, jobGroupList_all);
if (jobGroupList == null || jobGroupList.size() == 0) {
throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
}
model.addAttribute("JobGroupList", jobGroupList);
model.addAttribute("jobGroup", jobGroup);
return "jobinfo/jobinfo.index";
}
public static List<XxlJobGroup> filterJobGroupByRole(HttpServletRequest request, List<XxlJobGroup> jobGroupList_all) {
List<XxlJobGroup> jobGroupList = new ArrayList<>();
if (jobGroupList_all != null && jobGroupList_all.size() > 0) {
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
if (loginUser.getRole() == 1) {
jobGroupList = jobGroupList_all;
} else {
List<String> groupIdStrs = new ArrayList<>();
if (loginUser.getPermission() != null && loginUser.getPermission().trim().length() > 0) {
groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(","));
}
for (XxlJobGroup groupItem : jobGroupList_all) {
if (groupIdStrs.contains(String.valueOf(groupItem.getId()))) {
jobGroupList.add(groupItem);
}
}
}
}
return jobGroupList;
}
public static void validPermission(HttpServletRequest request, int jobGroup) {
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
if (!loginUser.validPermission(jobGroup)) {
throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username=" + loginUser.getUsername() + "]");
}
}
@RequestMapping("/pageList")
@ResponseBody
public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,
@RequestParam(required = false, defaultValue = "10") int length,
int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
return xxlJobService.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
}
@RequestMapping("/add")
@ResponseBody
public ReturnT<String> add(XxlJobInfo jobInfo) {
return xxlJobService.add(jobInfo);
}
@RequestMapping("/update")
@ResponseBody
public ReturnT<String> update(XxlJobInfo jobInfo) {
return xxlJobService.update(jobInfo);
}
@RequestMapping("/remove")
@ResponseBody
public ReturnT<String> remove(int id) {
return xxlJobService.remove(id);
}
@RequestMapping("/stop")
@ResponseBody
public ReturnT<String> pause(int id) {
return xxlJobService.stop(id);
}
@RequestMapping("/start")
@ResponseBody
public ReturnT<String> start(int id) {
return xxlJobService.start(id);
}
@RequestMapping("/trigger")
@ResponseBody
//@PermissionLimit(limit = false)
public ReturnT<String> triggerJob(int id, String executorParam, String addressList) {
// force cover job param
if (executorParam == null) {
executorParam = "";
}
JobTriggerPoolHelper.trigger(id, TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList);
return ReturnT.SUCCESS;
}
@RequestMapping("/nextTriggerTime")
@ResponseBody
public ReturnT<List<String>> nextTriggerTime(String scheduleType, String scheduleConf) {
XxlJobInfo paramXxlJobInfo = new XxlJobInfo();
paramXxlJobInfo.setScheduleType(scheduleType);
paramXxlJobInfo.setScheduleConf(scheduleConf);
List<String> result = new ArrayList<>();
try {
Date lastTime = new Date();
for (int i = 0; i < 5; i++) {
lastTime = JobScheduleHelper.generateNextValidTime(paramXxlJobInfo, lastTime);
if (lastTime != null) {
result.add(DateUtil.formatDateTime(lastTime));
} else {
break;
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new ReturnT<List<String>>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")) + e.getMessage());
}
return new ReturnT<List<String>>(result);
}
}

View File

@@ -1,238 +0,0 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.core.exception.XxlJobException;
import com.xxl.job.admin.core.complete.XxlJobCompleter;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogDao;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.KillParam;
import com.xxl.job.core.biz.model.LogParam;
import com.xxl.job.core.biz.model.LogResult;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* index controller
*
* @author xuxueli 2015-12-19 16:13:16
*/
@Controller
@RequestMapping("/joblog")
public class JobLogController {
private static Logger logger = LoggerFactory.getLogger(JobLogController.class);
@Resource
private XxlJobGroupDao xxlJobGroupDao;
@Resource
public XxlJobInfoDao xxlJobInfoDao;
@Resource
public XxlJobLogDao xxlJobLogDao;
@RequestMapping
public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "0") Integer jobId) {
// 执行器列表
List<XxlJobGroup> jobGroupList_all = xxlJobGroupDao.findAll();
// filter group
List<XxlJobGroup> jobGroupList = JobInfoController.filterJobGroupByRole(request, jobGroupList_all);
if (jobGroupList == null || jobGroupList.size() == 0) {
throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
}
model.addAttribute("JobGroupList", jobGroupList);
// 任务
if (jobId > 0) {
XxlJobInfo jobInfo = xxlJobInfoDao.loadById(jobId);
if (jobInfo == null) {
throw new RuntimeException(I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_unvalid"));
}
model.addAttribute("jobInfo", jobInfo);
// valid permission
JobInfoController.validPermission(request, jobInfo.getJobGroup());
}
return "joblog/joblog.index";
}
@RequestMapping("/getJobsByGroup")
@ResponseBody
public ReturnT<List<XxlJobInfo>> getJobsByGroup(int jobGroup) {
List<XxlJobInfo> list = xxlJobInfoDao.getJobsByGroup(jobGroup);
return new ReturnT<List<XxlJobInfo>>(list);
}
@RequestMapping("/pageList")
@ResponseBody
public Map<String, Object> pageList(HttpServletRequest request,
@RequestParam(required = false, defaultValue = "0") int start,
@RequestParam(required = false, defaultValue = "10") int length,
int jobGroup, int jobId, int logStatus, String filterTime) {
// valid permission
JobInfoController.validPermission(request, jobGroup); // 仅管理员支持查询全部;普通用户仅支持查询有权限的 jobGroup
// parse param
Date triggerTimeStart = null;
Date triggerTimeEnd = null;
if (filterTime != null && filterTime.trim().length() > 0) {
String[] temp = filterTime.split(" - ");
if (temp.length == 2) {
triggerTimeStart = DateUtil.parseDateTime(temp[0]);
triggerTimeEnd = DateUtil.parseDateTime(temp[1]);
}
}
// page query
List<XxlJobLog> list = xxlJobLogDao.pageList(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus);
int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus);
// package result
Map<String, Object> maps = new HashMap<String, Object>();
maps.put("recordsTotal", list_count); // 总记录数
maps.put("recordsFiltered", list_count); // 过滤后的总记录数
maps.put("data", list); // 分页列表
return maps;
}
@RequestMapping("/logDetailPage")
public String logDetailPage(int id, Model model) {
// base check
ReturnT<String> logStatue = ReturnT.SUCCESS;
XxlJobLog jobLog = xxlJobLogDao.load(id);
if (jobLog == null) {
throw new RuntimeException(I18nUtil.getString("joblog_logid_unvalid"));
}
model.addAttribute("triggerCode", jobLog.getTriggerCode());
model.addAttribute("handleCode", jobLog.getHandleCode());
model.addAttribute("logId", jobLog.getId());
return "joblog/joblog.detail";
}
@RequestMapping("/logDetailCat")
@ResponseBody
public ReturnT<LogResult> logDetailCat(long logId, int fromLineNum) {
try {
// valid
XxlJobLog jobLog = xxlJobLogDao.load(logId); // todo, need to improve performance
if (jobLog == null) {
return new ReturnT<LogResult>(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_logid_unvalid"));
}
// log cat
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(jobLog.getExecutorAddress());
ReturnT<LogResult> logResult = executorBiz.log(new LogParam(jobLog.getTriggerTime().getTime(), logId, fromLineNum));
// is end
if (logResult.getContent() != null && logResult.getContent().getFromLineNum() > logResult.getContent().getToLineNum()) {
if (jobLog.getHandleCode() > 0) {
logResult.getContent().setEnd(true);
}
}
return logResult;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new ReturnT<LogResult>(ReturnT.FAIL_CODE, e.getMessage());
}
}
@RequestMapping("/logKill")
@ResponseBody
public ReturnT<String> logKill(int id) {
// base check
XxlJobLog log = xxlJobLogDao.load(id);
XxlJobInfo jobInfo = xxlJobInfoDao.loadById(log.getJobId());
if (jobInfo == null) {
return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
}
if (ReturnT.SUCCESS_CODE != log.getTriggerCode()) {
return new ReturnT<String>(500, I18nUtil.getString("joblog_kill_log_limit"));
}
// request of kill
ReturnT<String> runResult = null;
try {
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(log.getExecutorAddress());
runResult = executorBiz.kill(new KillParam(jobInfo.getId()));
} catch (Exception e) {
logger.error(e.getMessage(), e);
runResult = new ReturnT<String>(500, e.getMessage());
}
if (ReturnT.SUCCESS_CODE == runResult.getCode()) {
log.setHandleCode(ReturnT.FAIL_CODE);
log.setHandleMsg(I18nUtil.getString("joblog_kill_log_byman") + ":" + (runResult.getMsg() != null ? runResult.getMsg() : ""));
log.setHandleTime(new Date());
XxlJobCompleter.updateHandleInfoAndFinish(log);
return new ReturnT<String>(runResult.getMsg());
} else {
return new ReturnT<String>(500, runResult.getMsg());
}
}
@RequestMapping("/clearLog")
@ResponseBody
public ReturnT<String> clearLog(int jobGroup, int jobId, int type) {
Date clearBeforeTime = null;
int clearBeforeNum = 0;
if (type == 1) {
clearBeforeTime = DateUtil.addMonths(new Date(), -1); // 清理一个月之前日志数据
} else if (type == 2) {
clearBeforeTime = DateUtil.addMonths(new Date(), -3); // 清理三个月之前日志数据
} else if (type == 3) {
clearBeforeTime = DateUtil.addMonths(new Date(), -6); // 清理六个月之前日志数据
} else if (type == 4) {
clearBeforeTime = DateUtil.addYears(new Date(), -1); // 清理一年之前日志数据
} else if (type == 5) {
clearBeforeNum = 1000; // 清理一千条以前日志数据
} else if (type == 6) {
clearBeforeNum = 10000; // 清理一万条以前日志数据
} else if (type == 7) {
clearBeforeNum = 30000; // 清理三万条以前日志数据
} else if (type == 8) {
clearBeforeNum = 100000; // 清理十万条以前日志数据
} else if (type == 9) {
clearBeforeNum = 0; // 清理所有日志数据
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_clean_type_unvalid"));
}
List<Long> logIds = null;
do {
logIds = xxlJobLogDao.findClearLogIds(jobGroup, jobId, clearBeforeTime, clearBeforeNum, 1000);
if (logIds != null && logIds.size() > 0) {
xxlJobLogDao.clearLog(logIds);
}
} while (logIds != null && logIds.size() > 0);
return ReturnT.SUCCESS;
}
}

View File

@@ -1,179 +0,0 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.dao.XxlJobUserDao;
import com.xxl.job.admin.service.LoginService;
import com.xxl.job.core.biz.model.ReturnT;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author xuxueli 2019-05-04 16:39:50
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Resource
private XxlJobUserDao xxlJobUserDao;
@Resource
private XxlJobGroupDao xxlJobGroupDao;
@RequestMapping
@PermissionLimit(adminuser = true)
public String index(Model model) {
// 执行器列表
List<XxlJobGroup> groupList = xxlJobGroupDao.findAll();
model.addAttribute("groupList", groupList);
return "user/user.index";
}
@RequestMapping("/pageList")
@ResponseBody
@PermissionLimit(adminuser = true)
public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,
@RequestParam(required = false, defaultValue = "10") int length,
String username, int role) {
// page list
List<XxlJobUser> list = xxlJobUserDao.pageList(start, length, username, role);
int list_count = xxlJobUserDao.pageListCount(start, length, username, role);
// filter
if (list != null && list.size() > 0) {
for (XxlJobUser item : list) {
item.setPassword(null);
}
}
// package result
Map<String, Object> maps = new HashMap<String, Object>();
maps.put("recordsTotal", list_count); // 总记录数
maps.put("recordsFiltered", list_count); // 过滤后的总记录数
maps.put("data", list); // 分页列表
return maps;
}
@RequestMapping("/add")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> add(XxlJobUser xxlJobUser) {
// valid username
if (!StringUtils.hasText(xxlJobUser.getUsername())) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input") + I18nUtil.getString("user_username"));
}
xxlJobUser.setUsername(xxlJobUser.getUsername().trim());
if (!(xxlJobUser.getUsername().length() >= 4 && xxlJobUser.getUsername().length() <= 20)) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]");
}
// valid password
if (!StringUtils.hasText(xxlJobUser.getPassword())) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input") + I18nUtil.getString("user_password"));
}
xxlJobUser.setPassword(xxlJobUser.getPassword().trim());
if (!(xxlJobUser.getPassword().length() >= 4 && xxlJobUser.getPassword().length() <= 20)) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]");
}
// md5 password
xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes()));
// check repeat
XxlJobUser existUser = xxlJobUserDao.loadByUserName(xxlJobUser.getUsername());
if (existUser != null) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("user_username_repeat"));
}
// write
xxlJobUserDao.save(xxlJobUser);
return ReturnT.SUCCESS;
}
@RequestMapping("/update")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> update(HttpServletRequest request, XxlJobUser xxlJobUser) {
// avoid opt login seft
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
if (loginUser.getUsername().equals(xxlJobUser.getUsername())) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit"));
}
// valid password
if (StringUtils.hasText(xxlJobUser.getPassword())) {
xxlJobUser.setPassword(xxlJobUser.getPassword().trim());
if (!(xxlJobUser.getPassword().length() >= 4 && xxlJobUser.getPassword().length() <= 20)) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]");
}
// md5 password
xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes()));
} else {
xxlJobUser.setPassword(null);
}
// write
xxlJobUserDao.update(xxlJobUser);
return ReturnT.SUCCESS;
}
@RequestMapping("/remove")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> remove(HttpServletRequest request, int id) {
// avoid opt login seft
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
if (loginUser.getId() == id) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit"));
}
xxlJobUserDao.delete(id);
return ReturnT.SUCCESS;
}
@RequestMapping("/updatePwd")
@ResponseBody
public ReturnT<String> updatePwd(HttpServletRequest request, String password) {
// valid password
if (password == null || password.trim().length() == 0) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), "密码不可为空");
}
password = password.trim();
if (!(password.length() >= 4 && password.length() <= 20)) {
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]");
}
// md5 password
String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
// update pwd
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
// do write
XxlJobUser existUser = xxlJobUserDao.loadByUserName(loginUser.getUsername());
existUser.setPassword(md5Password);
xxlJobUserDao.update(existUser);
return ReturnT.SUCCESS;
}
}

View File

@@ -1,30 +0,0 @@
package com.xxl.job.admin.controller.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 权限限制
*
* @author xuxueli 2015-12-12 18:29:02
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionLimit {
/**
* 登录拦截 (默认拦截)
*/
boolean limit() default true;
/**
* 要求管理员权限
*
* @return
*/
boolean adminuser() default false;
}

View File

@@ -1,42 +0,0 @@
package com.xxl.job.admin.controller.interceptor;
import com.xxl.job.admin.core.util.FtlUtil;
import com.xxl.job.admin.core.util.I18nUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
/**
* push cookies to model as cookieMap
*
* @author xuxueli 2015-12-12 18:09:04
*/
@Component
public class CookieInterceptor implements AsyncHandlerInterceptor {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// cookie
if (modelAndView != null && request.getCookies() != null && request.getCookies().length > 0) {
HashMap<String, Cookie> cookieMap = new HashMap<String, Cookie>();
for (Cookie ck : request.getCookies()) {
cookieMap.put(ck.getName(), ck);
}
modelAndView.addObject("cookieMap", cookieMap);
}
// static method
if (modelAndView != null) {
modelAndView.addObject("I18nUtil", FtlUtil.generateStaticModel(I18nUtil.class.getName()));
}
}
}

View File

@@ -1,59 +0,0 @@
package com.xxl.job.admin.controller.interceptor;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.service.LoginService;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 权限拦截
*
* @author xuxueli 2015-12-12 18:09:04
*/
@Component
public class PermissionInterceptor implements AsyncHandlerInterceptor {
@Resource
private LoginService loginService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true; // proceed with the next interceptor
}
// if need login
boolean needLogin = true;
boolean needAdminuser = false;
HandlerMethod method = (HandlerMethod) handler;
PermissionLimit permission = method.getMethodAnnotation(PermissionLimit.class);
if (permission != null) {
needLogin = permission.limit();
needAdminuser = permission.adminuser();
}
if (needLogin) {
XxlJobUser loginUser = loginService.ifLogin(request, response);
if (loginUser == null) {
response.setStatus(302);
response.setHeader("location", request.getContextPath() + "/toLogin");
return false;
}
if (needAdminuser && loginUser.getRole() != 1) {
throw new RuntimeException(I18nUtil.getString("system_permission_limit"));
}
request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser);
}
return true; // proceed with the next interceptor
}
}

View File

@@ -1,28 +0,0 @@
package com.xxl.job.admin.controller.interceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
/**
* web mvc config
*
* @author xuxueli 2018-04-02 20:48:20
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Resource
private PermissionInterceptor permissionInterceptor;
@Resource
private CookieInterceptor cookieInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
registry.addInterceptor(cookieInterceptor).addPathPatterns("/**");
}
}

View File

@@ -1,66 +0,0 @@
package com.xxl.job.admin.controller.resolver;
import com.xxl.job.admin.core.exception.XxlJobException;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.admin.core.util.JacksonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* common exception resolver
*
* @author xuxueli 2016-1-6 19:22:18
*/
@Component
public class WebExceptionResolver implements HandlerExceptionResolver {
private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
if (!(ex instanceof XxlJobException)) {
logger.error("WebExceptionResolver:{}", ex);
}
// if json
boolean isJson = false;
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler;
ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
if (responseBody != null) {
isJson = true;
}
}
// error result
ReturnT<String> errorResult = new ReturnT<String>(ReturnT.FAIL_CODE, ex.toString().replaceAll("\n", "<br/>"));
// response
ModelAndView mv = new ModelAndView();
if (isJson) {
try {
response.setContentType("application/json;charset=utf-8");
response.getWriter().print(JacksonUtil.writeValueAsString(errorResult));
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
return mv;
} else {
mv.addObject("exceptionMsg", errorResult.getMsg());
mv.setViewName("/common/common.exception");
return mv;
}
}
}

View File

@@ -1,20 +0,0 @@
package com.xxl.job.admin.core.alarm;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
/**
* @author xuxueli 2020-01-19
*/
public interface JobAlarm {
/**
* job alarm
*
* @param info
* @param jobLog
* @return
*/
public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog);
}

View File

@@ -1,65 +0,0 @@
package com.xxl.job.admin.core.alarm;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
public class JobAlarmer implements ApplicationContextAware, InitializingBean {
private static Logger logger = LoggerFactory.getLogger(JobAlarmer.class);
private ApplicationContext applicationContext;
private List<JobAlarm> jobAlarmList;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
Map<String, JobAlarm> serviceBeanMap = applicationContext.getBeansOfType(JobAlarm.class);
if (serviceBeanMap != null && serviceBeanMap.size() > 0) {
jobAlarmList = new ArrayList<JobAlarm>(serviceBeanMap.values());
}
}
/**
* job alarm
*
* @param info
* @param jobLog
* @return
*/
public boolean alarm(XxlJobInfo info, XxlJobLog jobLog) {
boolean result = false;
if (jobAlarmList != null && jobAlarmList.size() > 0) {
result = true; // success means all-success
for (JobAlarm alarm : jobAlarmList) {
boolean resultItem = false;
try {
resultItem = alarm.doAlarm(info, jobLog);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
if (!resultItem) {
result = false;
}
}
}
return result;
}
}

View File

@@ -1,118 +0,0 @@
package com.xxl.job.admin.core.alarm.impl;
import com.xxl.job.admin.core.alarm.JobAlarm;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.ReturnT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import javax.mail.internet.MimeMessage;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* job alarm by email
*
* @author xuxueli 2020-01-19
*/
@Component
public class EmailJobAlarm implements JobAlarm {
private static Logger logger = LoggerFactory.getLogger(EmailJobAlarm.class);
/**
* fail alarm
*
* @param jobLog
*/
@Override
public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog) {
boolean alarmResult = true;
// send monitor email
if (info != null && info.getAlarmEmail() != null && info.getAlarmEmail().trim().length() > 0) {
// alarmContent
String alarmContent = "Alarm Job LogId=" + jobLog.getId();
if (jobLog.getTriggerCode() != ReturnT.SUCCESS_CODE) {
alarmContent += "<br>TriggerMsg=<br>" + jobLog.getTriggerMsg();
}
if (jobLog.getHandleCode() > 0 && jobLog.getHandleCode() != ReturnT.SUCCESS_CODE) {
alarmContent += "<br>HandleCode=" + jobLog.getHandleMsg();
}
// email info
XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(Integer.valueOf(info.getJobGroup()));
String personal = I18nUtil.getString("admin_name_full");
String title = I18nUtil.getString("jobconf_monitor");
String content = MessageFormat.format(loadEmailJobAlarmTemplate(),
group != null ? group.getTitle() : "null",
info.getId(),
info.getJobDesc(),
alarmContent);
Set<String> emailSet = new HashSet<String>(Arrays.asList(info.getAlarmEmail().split(",")));
for (String email : emailSet) {
// make mail
try {
MimeMessage mimeMessage = XxlJobAdminConfig.getAdminConfig().getMailSender().createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(XxlJobAdminConfig.getAdminConfig().getEmailFrom(), personal);
helper.setTo(email);
helper.setSubject(title);
helper.setText(content, true);
XxlJobAdminConfig.getAdminConfig().getMailSender().send(mimeMessage);
} catch (Exception e) {
logger.error(">>>>>>>>>>> xxl-job, job fail alarm email send error, JobLogId:{}", jobLog.getId(), e);
alarmResult = false;
}
}
}
return alarmResult;
}
/**
* load email job alarm template
*
* @return
*/
private static final String loadEmailJobAlarmTemplate() {
String mailBodyTemplate = "<h5>" + I18nUtil.getString("jobconf_monitor_detail") + "</span>" +
"<table border=\"1\" cellpadding=\"3\" style=\"border-collapse:collapse; width:80%;\" >\n" +
" <thead style=\"font-weight: bold;color: #ffffff;background-color: #ff8c00;\" >" +
" <tr>\n" +
" <td width=\"20%\" >" + I18nUtil.getString("jobinfo_field_jobgroup") + "</td>\n" +
" <td width=\"10%\" >" + I18nUtil.getString("jobinfo_field_id") + "</td>\n" +
" <td width=\"20%\" >" + I18nUtil.getString("jobinfo_field_jobdesc") + "</td>\n" +
" <td width=\"10%\" >" + I18nUtil.getString("jobconf_monitor_alarm_title") + "</td>\n" +
" <td width=\"40%\" >" + I18nUtil.getString("jobconf_monitor_alarm_content") + "</td>\n" +
" </tr>\n" +
" </thead>\n" +
" <tbody>\n" +
" <tr>\n" +
" <td>{0}</td>\n" +
" <td>{1}</td>\n" +
" <td>{2}</td>\n" +
" <td>" + I18nUtil.getString("jobconf_monitor_alarm_type") + "</td>\n" +
" <td>{3}</td>\n" +
" </tr>\n" +
" </tbody>\n" +
"</table>";
return mailBodyTemplate;
}
}

View File

@@ -1,99 +0,0 @@
package com.xxl.job.admin.core.complete;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.MessageFormat;
/**
* @author xuxueli 2020-10-30 20:43:10
*/
public class XxlJobCompleter {
private static Logger logger = LoggerFactory.getLogger(XxlJobCompleter.class);
/**
* common fresh handle entrance (limit only once)
*
* @param xxlJobLog
* @return
*/
public static int updateHandleInfoAndFinish(XxlJobLog xxlJobLog) {
// finish
finishJob(xxlJobLog);
// text最大64kb 避免长度过长
if (xxlJobLog.getHandleMsg().length() > 15000) {
xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg().substring(0, 15000));
}
// fresh handle
return XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateHandleInfo(xxlJobLog);
}
/**
* do somethind to finish job
*/
private static void finishJob(XxlJobLog xxlJobLog) {
// 1、handle success, to trigger child job
String triggerChildMsg = null;
if (XxlJobContext.HANDLE_CODE_SUCCESS == xxlJobLog.getHandleCode()) {
XxlJobInfo xxlJobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(xxlJobLog.getJobId());
if (xxlJobInfo != null && xxlJobInfo.getChildJobId() != null && xxlJobInfo.getChildJobId().trim().length() > 0) {
triggerChildMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>" + I18nUtil.getString("jobconf_trigger_child_run") + "<<<<<<<<<<< </span><br>";
String[] childJobIds = xxlJobInfo.getChildJobId().split(",");
for (int i = 0; i < childJobIds.length; i++) {
int childJobId = (childJobIds[i] != null && childJobIds[i].trim().length() > 0 && isNumeric(childJobIds[i])) ? Integer.valueOf(childJobIds[i]) : -1;
if (childJobId > 0) {
JobTriggerPoolHelper.trigger(childJobId, TriggerTypeEnum.PARENT, -1, null, null, null);
ReturnT<String> triggerChildResult = ReturnT.SUCCESS;
// add msg
triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"),
(i + 1),
childJobIds.length,
childJobIds[i],
(triggerChildResult.getCode() == ReturnT.SUCCESS_CODE ? I18nUtil.getString("system_success") : I18nUtil.getString("system_fail")),
triggerChildResult.getMsg());
} else {
triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"),
(i + 1),
childJobIds.length,
childJobIds[i]);
}
}
}
}
if (triggerChildMsg != null) {
xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg() + triggerChildMsg);
}
// 2、fix_delay trigger next
// on the way
}
private static boolean isNumeric(String str) {
try {
int result = Integer.valueOf(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}

View File

@@ -1,159 +0,0 @@
package com.xxl.job.admin.core.conf;
import com.xxl.job.admin.core.alarm.JobAlarmer;
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
import com.xxl.job.admin.dao.*;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Arrays;
/**
* xxl-job config
*
* @author xuxueli 2017-04-28
*/
@Component
public class XxlJobAdminConfig implements InitializingBean, DisposableBean {
private static XxlJobAdminConfig adminConfig = null;
public static XxlJobAdminConfig getAdminConfig() {
return adminConfig;
}
// ---------------------- XxlJobScheduler ----------------------
private XxlJobScheduler xxlJobScheduler;
@Override
public void afterPropertiesSet() throws Exception {
adminConfig = this;
xxlJobScheduler = new XxlJobScheduler();
xxlJobScheduler.init();
}
@Override
public void destroy() throws Exception {
xxlJobScheduler.destroy();
}
// ---------------------- XxlJobScheduler ----------------------
// conf
@Value("${xxl.job.i18n}")
private String i18n;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${spring.mail.from}")
private String emailFrom;
@Value("${xxl.job.triggerpool.fast.max}")
private int triggerPoolFastMax;
@Value("${xxl.job.triggerpool.slow.max}")
private int triggerPoolSlowMax;
@Value("${xxl.job.logretentiondays}")
private int logretentiondays;
// dao, service
@Resource
private XxlJobLogDao xxlJobLogDao;
@Resource
private XxlJobInfoDao xxlJobInfoDao;
@Resource
private XxlJobRegistryDao xxlJobRegistryDao;
@Resource
private XxlJobGroupDao xxlJobGroupDao;
@Resource
private XxlJobLogReportDao xxlJobLogReportDao;
@Resource
private JavaMailSender mailSender;
@Resource
private DataSource dataSource;
@Resource
private JobAlarmer jobAlarmer;
public String getI18n() {
if (!Arrays.asList("zh_CN", "zh_TC", "en").contains(i18n)) {
return "zh_CN";
}
return i18n;
}
public String getAccessToken() {
return accessToken;
}
public String getEmailFrom() {
return emailFrom;
}
public int getTriggerPoolFastMax() {
if (triggerPoolFastMax < 200) {
return 200;
}
return triggerPoolFastMax;
}
public int getTriggerPoolSlowMax() {
if (triggerPoolSlowMax < 100) {
return 100;
}
return triggerPoolSlowMax;
}
public int getLogretentiondays() {
if (logretentiondays < 7) {
return -1; // Limit greater than or equal to 7, otherwise close
}
return logretentiondays;
}
public XxlJobLogDao getXxlJobLogDao() {
return xxlJobLogDao;
}
public XxlJobInfoDao getXxlJobInfoDao() {
return xxlJobInfoDao;
}
public XxlJobRegistryDao getXxlJobRegistryDao() {
return xxlJobRegistryDao;
}
public XxlJobGroupDao getXxlJobGroupDao() {
return xxlJobGroupDao;
}
public XxlJobLogReportDao getXxlJobLogReportDao() {
return xxlJobLogReportDao;
}
public JavaMailSender getMailSender() {
return mailSender;
}
public DataSource getDataSource() {
return dataSource;
}
public JobAlarmer getJobAlarmer() {
return jobAlarmer;
}
}

View File

@@ -1,15 +0,0 @@
package com.xxl.job.admin.core.exception;
/**
* @author xuxueli 2019-05-04 23:19:29
*/
public class XxlJobException extends RuntimeException {
public XxlJobException() {
}
public XxlJobException(String message) {
super(message);
}
}

View File

@@ -1,78 +0,0 @@
package com.xxl.job.admin.core.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* Created by xuxueli on 16/9/30.
*/
public class XxlJobGroup {
private int id;
private String appname;
private String title;
private int addressType; // 执行器地址类型0=自动注册、1=手动录入
private String addressList; // 执行器地址列表,多地址逗号分隔(手动录入)
private Date updateTime;
// registry list
private List<String> registryList; // 执行器地址列表(系统注册)
public List<String> getRegistryList() {
if (addressList != null && addressList.trim().length() > 0) {
registryList = new ArrayList<String>(Arrays.asList(addressList.split(",")));
}
return registryList;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAppname() {
return appname;
}
public void setAppname(String appname) {
this.appname = appname;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getAddressType() {
return addressType;
}
public void setAddressType(int addressType) {
this.addressType = addressType;
}
public String getAddressList() {
return addressList;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public void setAddressList(String addressList) {
this.addressList = addressList;
}
}

View File

@@ -1,237 +0,0 @@
package com.xxl.job.admin.core.model;
import java.util.Date;
/**
* xxl-job info
*
* @author xuxueli 2016-1-12 18:25:49
*/
public class XxlJobInfo {
private int id; // 主键ID
private int jobGroup; // 执行器主键ID
private String jobDesc;
private Date addTime;
private Date updateTime;
private String author; // 负责人
private String alarmEmail; // 报警邮件
private String scheduleType; // 调度类型
private String scheduleConf; // 调度配置,值含义取决于调度类型
private String misfireStrategy; // 调度过期策略
private String executorRouteStrategy; // 执行器路由策略
private String executorHandler; // 执行器任务Handler名称
private String executorParam; // 执行器,任务参数
private String executorBlockStrategy; // 阻塞处理策略
private int executorTimeout; // 任务执行超时时间,单位秒
private int executorFailRetryCount; // 失败重试次数
private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum
private String glueSource; // GLUE源代码
private String glueRemark; // GLUE备注
private Date glueUpdatetime; // GLUE更新时间
private String childJobId; // 子任务ID多个逗号分隔
private int triggerStatus; // 调度状态0-停止1-运行
private long triggerLastTime; // 上次调度时间
private long triggerNextTime; // 下次调度时间
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getJobGroup() {
return jobGroup;
}
public void setJobGroup(int jobGroup) {
this.jobGroup = jobGroup;
}
public String getJobDesc() {
return jobDesc;
}
public void setJobDesc(String jobDesc) {
this.jobDesc = jobDesc;
}
public Date getAddTime() {
return addTime;
}
public void setAddTime(Date addTime) {
this.addTime = addTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getAlarmEmail() {
return alarmEmail;
}
public void setAlarmEmail(String alarmEmail) {
this.alarmEmail = alarmEmail;
}
public String getScheduleType() {
return scheduleType;
}
public void setScheduleType(String scheduleType) {
this.scheduleType = scheduleType;
}
public String getScheduleConf() {
return scheduleConf;
}
public void setScheduleConf(String scheduleConf) {
this.scheduleConf = scheduleConf;
}
public String getMisfireStrategy() {
return misfireStrategy;
}
public void setMisfireStrategy(String misfireStrategy) {
this.misfireStrategy = misfireStrategy;
}
public String getExecutorRouteStrategy() {
return executorRouteStrategy;
}
public void setExecutorRouteStrategy(String executorRouteStrategy) {
this.executorRouteStrategy = executorRouteStrategy;
}
public String getExecutorHandler() {
return executorHandler;
}
public void setExecutorHandler(String executorHandler) {
this.executorHandler = executorHandler;
}
public String getExecutorParam() {
return executorParam;
}
public void setExecutorParam(String executorParam) {
this.executorParam = executorParam;
}
public String getExecutorBlockStrategy() {
return executorBlockStrategy;
}
public void setExecutorBlockStrategy(String executorBlockStrategy) {
this.executorBlockStrategy = executorBlockStrategy;
}
public int getExecutorTimeout() {
return executorTimeout;
}
public void setExecutorTimeout(int executorTimeout) {
this.executorTimeout = executorTimeout;
}
public int getExecutorFailRetryCount() {
return executorFailRetryCount;
}
public void setExecutorFailRetryCount(int executorFailRetryCount) {
this.executorFailRetryCount = executorFailRetryCount;
}
public String getGlueType() {
return glueType;
}
public void setGlueType(String glueType) {
this.glueType = glueType;
}
public String getGlueSource() {
return glueSource;
}
public void setGlueSource(String glueSource) {
this.glueSource = glueSource;
}
public String getGlueRemark() {
return glueRemark;
}
public void setGlueRemark(String glueRemark) {
this.glueRemark = glueRemark;
}
public Date getGlueUpdatetime() {
return glueUpdatetime;
}
public void setGlueUpdatetime(Date glueUpdatetime) {
this.glueUpdatetime = glueUpdatetime;
}
public String getChildJobId() {
return childJobId;
}
public void setChildJobId(String childJobId) {
this.childJobId = childJobId;
}
public int getTriggerStatus() {
return triggerStatus;
}
public void setTriggerStatus(int triggerStatus) {
this.triggerStatus = triggerStatus;
}
public long getTriggerLastTime() {
return triggerLastTime;
}
public void setTriggerLastTime(long triggerLastTime) {
this.triggerLastTime = triggerLastTime;
}
public long getTriggerNextTime() {
return triggerNextTime;
}
public void setTriggerNextTime(long triggerNextTime) {
this.triggerNextTime = triggerNextTime;
}
}

View File

@@ -1,158 +0,0 @@
package com.xxl.job.admin.core.model;
import java.util.Date;
/**
* xxl-job log, used to track trigger process
*
* @author xuxueli 2015-12-19 23:19:09
*/
public class XxlJobLog {
private long id;
// job info
private int jobGroup;
private int jobId;
// execute info
private String executorAddress;
private String executorHandler;
private String executorParam;
private String executorShardingParam;
private int executorFailRetryCount;
// trigger info
private Date triggerTime;
private int triggerCode;
private String triggerMsg;
// handle info
private Date handleTime;
private int handleCode;
private String handleMsg;
// alarm info
private int alarmStatus;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public int getJobGroup() {
return jobGroup;
}
public void setJobGroup(int jobGroup) {
this.jobGroup = jobGroup;
}
public int getJobId() {
return jobId;
}
public void setJobId(int jobId) {
this.jobId = jobId;
}
public String getExecutorAddress() {
return executorAddress;
}
public void setExecutorAddress(String executorAddress) {
this.executorAddress = executorAddress;
}
public String getExecutorHandler() {
return executorHandler;
}
public void setExecutorHandler(String executorHandler) {
this.executorHandler = executorHandler;
}
public String getExecutorParam() {
return executorParam;
}
public void setExecutorParam(String executorParam) {
this.executorParam = executorParam;
}
public String getExecutorShardingParam() {
return executorShardingParam;
}
public void setExecutorShardingParam(String executorShardingParam) {
this.executorShardingParam = executorShardingParam;
}
public int getExecutorFailRetryCount() {
return executorFailRetryCount;
}
public void setExecutorFailRetryCount(int executorFailRetryCount) {
this.executorFailRetryCount = executorFailRetryCount;
}
public Date getTriggerTime() {
return triggerTime;
}
public void setTriggerTime(Date triggerTime) {
this.triggerTime = triggerTime;
}
public int getTriggerCode() {
return triggerCode;
}
public void setTriggerCode(int triggerCode) {
this.triggerCode = triggerCode;
}
public String getTriggerMsg() {
return triggerMsg;
}
public void setTriggerMsg(String triggerMsg) {
this.triggerMsg = triggerMsg;
}
public Date getHandleTime() {
return handleTime;
}
public void setHandleTime(Date handleTime) {
this.handleTime = handleTime;
}
public int getHandleCode() {
return handleCode;
}
public void setHandleCode(int handleCode) {
this.handleCode = handleCode;
}
public String getHandleMsg() {
return handleMsg;
}
public void setHandleMsg(String handleMsg) {
this.handleMsg = handleMsg;
}
public int getAlarmStatus() {
return alarmStatus;
}
public void setAlarmStatus(int alarmStatus) {
this.alarmStatus = alarmStatus;
}
}

View File

@@ -1,76 +0,0 @@
package com.xxl.job.admin.core.model;
import java.util.Date;
/**
* xxl-job log for glue, used to track job code process
*
* @author xuxueli 2016-5-19 17:57:46
*/
public class XxlJobLogGlue {
private int id;
private int jobId; // 任务主键ID
private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum
private String glueSource;
private String glueRemark;
private Date addTime;
private Date updateTime;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getJobId() {
return jobId;
}
public void setJobId(int jobId) {
this.jobId = jobId;
}
public String getGlueType() {
return glueType;
}
public void setGlueType(String glueType) {
this.glueType = glueType;
}
public String getGlueSource() {
return glueSource;
}
public void setGlueSource(String glueSource) {
this.glueSource = glueSource;
}
public String getGlueRemark() {
return glueRemark;
}
public void setGlueRemark(String glueRemark) {
this.glueRemark = glueRemark;
}
public Date getAddTime() {
return addTime;
}
public void setAddTime(Date addTime) {
this.addTime = addTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
}

Some files were not shown because too many files have changed in this diff Show More