init
This commit is contained in:
		@ -0,0 +1,70 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import cn.dev33.satoken.annotation.SaIgnore;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.mail.utils.MailUtils;
 | 
			
		||||
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;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 邮件发送案例
 | 
			
		||||
 *
 | 
			
		||||
 * @author Michelle.Chung
 | 
			
		||||
 */
 | 
			
		||||
@SaIgnore
 | 
			
		||||
@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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 发送邮件(多附件)
 | 
			
		||||
     *
 | 
			
		||||
     * @param to       接收人
 | 
			
		||||
     * @param subject  标题
 | 
			
		||||
     * @param text     内容
 | 
			
		||||
     * @param paths    附件路径
 | 
			
		||||
     */
 | 
			
		||||
    @GetMapping("/sendMessageWithAttachments")
 | 
			
		||||
    public R<Void> sendMessageWithAttachments(String to, String subject, String text, String[] paths) {
 | 
			
		||||
        File[] array = Arrays.stream(paths).map(File::new).toArray(File[]::new);
 | 
			
		||||
        MailUtils.sendText(to, subject, text, array);
 | 
			
		||||
        return R.ok();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,92 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.thread.ThreadUtil;
 | 
			
		||||
import org.dromara.common.core.constant.CacheNames;
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.redis.utils.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);
 | 
			
		||||
        ThreadUtil.sleep(11 * 1000);
 | 
			
		||||
        Object obj = RedisUtils.getCacheObject(key);
 | 
			
		||||
        return R.ok(value.equals(obj));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,64 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.thread.ThreadUtil;
 | 
			
		||||
import com.baomidou.lock.LockInfo;
 | 
			
		||||
import com.baomidou.lock.LockTemplate;
 | 
			
		||||
import com.baomidou.lock.annotation.Lock4j;
 | 
			
		||||
import com.baomidou.lock.executor.RedissonLockExecutor;
 | 
			
		||||
import org.dromara.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());
 | 
			
		||||
        ThreadUtil.sleep(10000);
 | 
			
		||||
        System.out.println("end :" + key + ",time:" + LocalTime.now());
 | 
			
		||||
        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 {
 | 
			
		||||
            ThreadUtil.sleep(8000);
 | 
			
		||||
            System.out.println("执行简单方法1 , 当前线程:" + Thread.currentThread().getName());
 | 
			
		||||
        } finally {
 | 
			
		||||
            //释放锁
 | 
			
		||||
            lockTemplate.releaseLock(lockInfo);
 | 
			
		||||
        }
 | 
			
		||||
        //结束
 | 
			
		||||
        return R.ok("操作成功", value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,47 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.redis.utils.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("操作成功");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,64 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.ratelimiter.annotation.RateLimiter;
 | 
			
		||||
import org.dromara.common.ratelimiter.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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,82 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.sms4j.api.SmsBlend;
 | 
			
		||||
import org.dromara.sms4j.api.entity.SmsResponse;
 | 
			
		||||
import org.dromara.sms4j.core.factory.SmsFactory;
 | 
			
		||||
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.getSmsBlend("config1");
 | 
			
		||||
        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.getSmsBlend("config2");
 | 
			
		||||
        SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map);
 | 
			
		||||
        return R.ok(smsResponse);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 添加黑名单
 | 
			
		||||
     *
 | 
			
		||||
     * @param phone 手机号
 | 
			
		||||
     */
 | 
			
		||||
    @GetMapping("/addBlacklist")
 | 
			
		||||
    public R<Object> addBlacklist(String phone){
 | 
			
		||||
        SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
 | 
			
		||||
        smsBlend.joinInBlacklist(phone);
 | 
			
		||||
        return R.ok();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 移除黑名单
 | 
			
		||||
     *
 | 
			
		||||
     * @param phone 手机号
 | 
			
		||||
     */
 | 
			
		||||
    @GetMapping("/removeBlacklist")
 | 
			
		||||
    public R<Object> removeBlacklist(String phone){
 | 
			
		||||
        SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
 | 
			
		||||
        smsBlend.removeFromBlacklist(phone);
 | 
			
		||||
        return R.ok();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,31 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import org.dromara.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());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,90 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.web.core.BaseController;
 | 
			
		||||
import org.dromara.demo.domain.TestDemo;
 | 
			
		||||
import org.dromara.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)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,147 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import cn.dev33.satoken.annotation.SaCheckPermission;
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.core.utils.MapstructUtils;
 | 
			
		||||
import org.dromara.common.core.utils.ValidatorUtils;
 | 
			
		||||
import org.dromara.common.core.validate.AddGroup;
 | 
			
		||||
import org.dromara.common.core.validate.EditGroup;
 | 
			
		||||
import org.dromara.common.core.validate.QueryGroup;
 | 
			
		||||
import org.dromara.common.web.core.BaseController;
 | 
			
		||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.PageQuery;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
 | 
			
		||||
import org.dromara.common.excel.core.ExcelResult;
 | 
			
		||||
import org.dromara.common.excel.utils.ExcelUtil;
 | 
			
		||||
import org.dromara.common.log.annotation.Log;
 | 
			
		||||
import org.dromara.common.log.enums.BusinessType;
 | 
			
		||||
import org.dromara.demo.domain.TestDemo;
 | 
			
		||||
import org.dromara.demo.domain.bo.TestDemoBo;
 | 
			
		||||
import org.dromara.demo.domain.bo.TestDemoImportVo;
 | 
			
		||||
import org.dromara.demo.domain.vo.TestDemoVo;
 | 
			
		||||
import org.dromara.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 jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
import jakarta.validation.constraints.NotEmpty;
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
 | 
			
		||||
import java.util.*;
 | 
			
		||||
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 testDemoService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询测试单表列表
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("demo:demo:list")
 | 
			
		||||
    @GetMapping("/list")
 | 
			
		||||
    public TableDataInfo<TestDemoVo> list(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) {
 | 
			
		||||
        return testDemoService.queryPageList(bo, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 自定义分页查询
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("demo:demo:list")
 | 
			
		||||
    @GetMapping("/page")
 | 
			
		||||
    public TableDataInfo<TestDemoVo> page(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) {
 | 
			
		||||
        return testDemoService.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<TestDemo> list = MapstructUtils.convert(excelResult.getList(), TestDemo.class);
 | 
			
		||||
        testDemoService.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 = testDemoService.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(testDemoService.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(testDemoService.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(testDemoService.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(testDemoService.deleteWithValidByIds(Arrays.asList(ids), true));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,55 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.demo.domain.TestDemoEncrypt;
 | 
			
		||||
import org.dromara.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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,160 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.dromara.common.excel.core.ExcelResult;
 | 
			
		||||
import org.dromara.common.excel.utils.ExcelUtil;
 | 
			
		||||
import org.dromara.demo.domain.vo.ExportDemoVo;
 | 
			
		||||
import org.dromara.demo.listener.ExportDemoListener;
 | 
			
		||||
import org.dromara.demo.service.IExportExcelService;
 | 
			
		||||
import org.springframework.http.MediaType;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
import org.springframework.web.multipart.MultipartFile;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 测试Excel功能
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 */
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
@RestController
 | 
			
		||||
@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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 多个sheet导出
 | 
			
		||||
     */
 | 
			
		||||
    @GetMapping("/exportTemplateMultiSheet")
 | 
			
		||||
    public void exportTemplateMultiSheet(HttpServletResponse response) {
 | 
			
		||||
        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"));
 | 
			
		||||
        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"));
 | 
			
		||||
        list3.add(new TestObj1("list3测试4", "list3测试5", "list3测试6"));
 | 
			
		||||
        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"));
 | 
			
		||||
 | 
			
		||||
        List<Map<String, Object>> list = new ArrayList<>();
 | 
			
		||||
        Map<String, Object> sheetMap1 = new HashMap<>();
 | 
			
		||||
        sheetMap1.put("data1", list1);
 | 
			
		||||
        Map<String, Object> sheetMap2 = new HashMap<>();
 | 
			
		||||
        sheetMap2.put("data2", list2);
 | 
			
		||||
        Map<String, Object> sheetMap3 = new HashMap<>();
 | 
			
		||||
        sheetMap3.put("data3", list3);
 | 
			
		||||
        Map<String, Object> sheetMap4 = new HashMap<>();
 | 
			
		||||
        sheetMap4.put("data4", list4);
 | 
			
		||||
 | 
			
		||||
        list.add(sheetMap1);
 | 
			
		||||
        list.add(sheetMap2);
 | 
			
		||||
        list.add(sheetMap3);
 | 
			
		||||
        list.add(sheetMap4);
 | 
			
		||||
        ExcelUtil.exportTemplateMultiSheet(list, "多sheet列表", "excel/多sheet列表.xlsx", 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,71 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.core.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 jakarta.validation.constraints.NotBlank;
 | 
			
		||||
import jakarta.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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,76 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.web.core.BaseController;
 | 
			
		||||
import org.dromara.common.sensitive.annotation.Sensitive;
 | 
			
		||||
import org.dromara.common.sensitive.core.SensitiveStrategy;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.dromara.common.sensitive.core.SensitiveService;
 | 
			
		||||
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 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, roleKey = "common")
 | 
			
		||||
        private String phone;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 地址
 | 
			
		||||
         */
 | 
			
		||||
        @Sensitive(strategy = SensitiveStrategy.ADDRESS, perms = "system:user:query")
 | 
			
		||||
        private String address;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 邮箱
 | 
			
		||||
         */
 | 
			
		||||
        @Sensitive(strategy = SensitiveStrategy.EMAIL, roleKey = "common", perms = "system:user:query1")
 | 
			
		||||
        private String email;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 银行卡
 | 
			
		||||
         */
 | 
			
		||||
        @Sensitive(strategy = SensitiveStrategy.BANK_CARD, roleKey = "common1", perms = "system:user:query")
 | 
			
		||||
        private String bankCard;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,107 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import cn.dev33.satoken.annotation.SaCheckPermission;
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.core.validate.AddGroup;
 | 
			
		||||
import org.dromara.common.core.validate.EditGroup;
 | 
			
		||||
import org.dromara.common.core.validate.QueryGroup;
 | 
			
		||||
import org.dromara.common.web.core.BaseController;
 | 
			
		||||
import org.dromara.common.excel.utils.ExcelUtil;
 | 
			
		||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
 | 
			
		||||
import org.dromara.common.log.annotation.Log;
 | 
			
		||||
import org.dromara.common.log.enums.BusinessType;
 | 
			
		||||
import org.dromara.demo.domain.bo.TestTreeBo;
 | 
			
		||||
import org.dromara.demo.domain.vo.TestTreeVo;
 | 
			
		||||
import org.dromara.demo.service.ITestTreeService;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
import jakarta.validation.constraints.NotEmpty;
 | 
			
		||||
import jakarta.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 testTreeService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询测试树表列表
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("demo:tree:list")
 | 
			
		||||
    @GetMapping("/list")
 | 
			
		||||
    public R<List<TestTreeVo>> list(@Validated(QueryGroup.class) TestTreeBo bo) {
 | 
			
		||||
        List<TestTreeVo> list = testTreeService.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 = testTreeService.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(testTreeService.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(testTreeService.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(testTreeService.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(testTreeService.deleteWithValidByIds(Arrays.asList(ids), true));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,33 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.websocket.dto.WebSocketMessageDto;
 | 
			
		||||
import org.dromara.common.websocket.utils.WebSocketUtils;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * WebSocket 演示案例
 | 
			
		||||
 *
 | 
			
		||||
 * @author zendwang
 | 
			
		||||
 */
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("/demo/websocket")
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class WeSocketController {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 发布消息
 | 
			
		||||
     *
 | 
			
		||||
     * @param dto 发送内容
 | 
			
		||||
     */
 | 
			
		||||
    @GetMapping("/send")
 | 
			
		||||
    public R<Void> send(WebSocketMessageDto dto) throws InterruptedException {
 | 
			
		||||
        WebSocketUtils.publishMessage(dto);
 | 
			
		||||
        return R.ok("操作成功");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1 @@
 | 
			
		||||
package org.dromara.demo.controller;
 | 
			
		||||
@ -0,0 +1,92 @@
 | 
			
		||||
package org.dromara.demo.controller.queue;
 | 
			
		||||
 | 
			
		||||
import cn.dev33.satoken.annotation.SaIgnore;
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.redis.utils.QueueUtils;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.redisson.api.RBoundedBlockingQueue;
 | 
			
		||||
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("操作成功");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,97 @@
 | 
			
		||||
package org.dromara.demo.controller.queue;
 | 
			
		||||
 | 
			
		||||
import cn.dev33.satoken.annotation.SaIgnore;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.redis.utils.QueueUtils;
 | 
			
		||||
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.CompletableFuture;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 延迟队列 演示案例
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 轻量级队列 重量级数据量 请使用 MQ
 | 
			
		||||
 * 例如: 创建订单30分钟后过期处理
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 集群测试通过 同一个数据只会被消费一次 做好事务补偿
 | 
			
		||||
 * 集群测试流程 两台集群分别开启订阅 在其中一台发送数据 观察接收消息的规律
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 * @version 3.6.0
 | 
			
		||||
 */
 | 
			
		||||
@SaIgnore
 | 
			
		||||
@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);
 | 
			
		||||
            return CompletableFuture.runAsync(() -> {
 | 
			
		||||
                // 异步处理数据逻辑 不要在上方处理业务逻辑
 | 
			
		||||
                log.info("数据处理: {}", 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("操作成功");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,22 @@
 | 
			
		||||
package org.dromara.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());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,89 @@
 | 
			
		||||
package org.dromara.demo.controller.queue;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.util.RandomUtil;
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.redis.utils.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("操作成功");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,68 @@
 | 
			
		||||
package org.dromara.demo.domain;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.*;
 | 
			
		||||
import org.dromara.common.tenant.core.TenantEntity;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 测试单表对象 test_demo
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 * @date 2021-07-26
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@TableName("test_demo")
 | 
			
		||||
public class TestDemo extends TenantEntity {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,29 @@
 | 
			
		||||
package org.dromara.demo.domain;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableName;
 | 
			
		||||
import org.dromara.common.encrypt.annotation.EncryptField;
 | 
			
		||||
import org.dromara.common.encrypt.enumd.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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,65 @@
 | 
			
		||||
package org.dromara.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 org.dromara.common.tenant.core.TenantEntity;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 测试树表对象 test_tree
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 * @date 2021-07-26
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@TableName("test_tree")
 | 
			
		||||
public class TestTree extends TenantEntity {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键
 | 
			
		||||
     */
 | 
			
		||||
    @TableId(value = "id")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 父ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long parentId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 部门id
 | 
			
		||||
     */
 | 
			
		||||
    private Long deptId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户id
 | 
			
		||||
     */
 | 
			
		||||
    private Long userId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 树节点名
 | 
			
		||||
     */
 | 
			
		||||
    private String treeName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 版本
 | 
			
		||||
     */
 | 
			
		||||
    @Version
 | 
			
		||||
    private Long version;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除标志
 | 
			
		||||
     */
 | 
			
		||||
    @TableLogic
 | 
			
		||||
    private Long delFlag;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,62 @@
 | 
			
		||||
package org.dromara.demo.domain.bo;
 | 
			
		||||
 | 
			
		||||
import org.dromara.common.core.validate.AddGroup;
 | 
			
		||||
import org.dromara.common.core.validate.EditGroup;
 | 
			
		||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
 | 
			
		||||
import org.dromara.demo.domain.TestDemo;
 | 
			
		||||
import io.github.linpeilie.annotations.AutoMapper;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
 | 
			
		||||
import jakarta.validation.constraints.NotBlank;
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 测试单表业务对象 test_demo
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 * @date 2021-07-26
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@AutoMapper(target = TestDemo.class, reverseConvertGenerate = false)
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,53 @@
 | 
			
		||||
package org.dromara.demo.domain.bo;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelProperty;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import jakarta.validation.constraints.NotBlank;
 | 
			
		||||
import jakarta.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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,54 @@
 | 
			
		||||
package org.dromara.demo.domain.bo;
 | 
			
		||||
 | 
			
		||||
import org.dromara.common.core.validate.AddGroup;
 | 
			
		||||
import org.dromara.common.core.validate.EditGroup;
 | 
			
		||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
 | 
			
		||||
import org.dromara.demo.domain.TestTree;
 | 
			
		||||
import io.github.linpeilie.annotations.AutoMapper;
 | 
			
		||||
import jakarta.validation.constraints.NotBlank;
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 测试树表业务对象 test_tree
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 * @date 2021-07-26
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@AutoMapper(target = TestTree.class, reverseConvertGenerate = false)
 | 
			
		||||
public class TestTreeBo extends BaseEntity {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "主键不能为空", groups = {EditGroup.class})
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 父ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long parentId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 部门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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1 @@
 | 
			
		||||
package org.dromara.demo.domain;
 | 
			
		||||
@ -0,0 +1,122 @@
 | 
			
		||||
package org.dromara.demo.domain.vo;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelProperty;
 | 
			
		||||
import jakarta.validation.constraints.NotEmpty;
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import org.dromara.common.core.enums.UserStatus;
 | 
			
		||||
import org.dromara.common.core.validate.AddGroup;
 | 
			
		||||
import org.dromara.common.core.validate.EditGroup;
 | 
			
		||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
 | 
			
		||||
import org.dromara.common.excel.annotation.ExcelEnumFormat;
 | 
			
		||||
import org.dromara.common.excel.convert.ExcelDictConvert;
 | 
			
		||||
import org.dromara.common.excel.convert.ExcelEnumConvert;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 带有下拉选的Excel导出
 | 
			
		||||
 *
 | 
			
		||||
 * @author Emil.Zhang
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@ExcelIgnoreUnannotated
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
public class ExportDemoVo implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,111 @@
 | 
			
		||||
package org.dromara.demo.domain.vo;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelProperty;
 | 
			
		||||
import org.dromara.common.excel.annotation.ExcelNotation;
 | 
			
		||||
import org.dromara.common.excel.annotation.ExcelRequired;
 | 
			
		||||
import org.dromara.common.translation.annotation.Translation;
 | 
			
		||||
import org.dromara.common.translation.constant.TransConstant;
 | 
			
		||||
import org.dromara.demo.domain.TestDemo;
 | 
			
		||||
import io.github.linpeilie.annotations.AutoMapper;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 测试单表视图对象 test_demo
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 * @date 2021-07-26
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@ExcelIgnoreUnannotated
 | 
			
		||||
@AutoMapper(target = TestDemo.class)
 | 
			
		||||
public class TestDemoVo implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "主键")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 部门id
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelRequired
 | 
			
		||||
    @ExcelProperty(value = "部门id")
 | 
			
		||||
    private Long deptId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户id
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelRequired
 | 
			
		||||
    @ExcelProperty(value = "用户id")
 | 
			
		||||
    private Long userId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 排序号
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelRequired
 | 
			
		||||
    @ExcelProperty(value = "排序号")
 | 
			
		||||
    private Integer orderNum;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * key键
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelNotation(value = "测试key")
 | 
			
		||||
    @ExcelProperty(value = "key键")
 | 
			
		||||
    private String testKey;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 值
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelNotation(value = "测试value")
 | 
			
		||||
    @ExcelProperty(value = "值")
 | 
			
		||||
    private String value;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建时间
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "创建时间")
 | 
			
		||||
    private Date createTime;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建人
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "创建人")
 | 
			
		||||
    private Long createBy;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建人账号
 | 
			
		||||
     */
 | 
			
		||||
    @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy")
 | 
			
		||||
    @ExcelProperty(value = "创建人账号")
 | 
			
		||||
    private String createByName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新时间
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "更新时间")
 | 
			
		||||
    private Date updateTime;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新人
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "更新人")
 | 
			
		||||
    private Long updateBy;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新人账号
 | 
			
		||||
     */
 | 
			
		||||
    @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "updateBy")
 | 
			
		||||
    @ExcelProperty(value = "更新人账号")
 | 
			
		||||
    private String updateByName;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,64 @@
 | 
			
		||||
package org.dromara.demo.domain.vo;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelProperty;
 | 
			
		||||
import org.dromara.demo.domain.TestTree;
 | 
			
		||||
import io.github.linpeilie.annotations.AutoMapper;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 测试树表视图对象 test_tree
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 * @date 2021-07-26
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@ExcelIgnoreUnannotated
 | 
			
		||||
@AutoMapper(target = TestTree.class)
 | 
			
		||||
public class TestTreeVo implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,68 @@
 | 
			
		||||
package org.dromara.demo.listener;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.util.NumberUtil;
 | 
			
		||||
import com.alibaba.excel.context.AnalysisContext;
 | 
			
		||||
import org.dromara.common.core.utils.ValidatorUtils;
 | 
			
		||||
import org.dromara.common.core.validate.AddGroup;
 | 
			
		||||
import org.dromara.common.core.validate.EditGroup;
 | 
			
		||||
import org.dromara.common.excel.core.DefaultExcelListener;
 | 
			
		||||
import org.dromara.common.excel.core.DropDownOptions;
 | 
			
		||||
import org.dromara.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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,13 @@
 | 
			
		||||
package org.dromara.demo.mapper;
 | 
			
		||||
 | 
			
		||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 | 
			
		||||
import org.dromara.demo.domain.TestDemoEncrypt;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 测试加密功能
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 */
 | 
			
		||||
public interface TestDemoEncryptMapper extends BaseMapperPlus<TestDemoEncrypt, TestDemoEncrypt> {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,64 @@
 | 
			
		||||
package org.dromara.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 org.apache.ibatis.annotations.Param;
 | 
			
		||||
import org.dromara.common.mybatis.annotation.DataColumn;
 | 
			
		||||
import org.dromara.common.mybatis.annotation.DataPermission;
 | 
			
		||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 | 
			
		||||
import org.dromara.demo.domain.TestDemo;
 | 
			
		||||
import org.dromara.demo.domain.vo.TestDemoVo;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 测试单表Mapper接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 * @date 2021-07-26
 | 
			
		||||
 */
 | 
			
		||||
public interface TestDemoMapper extends BaseMapperPlus<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")
 | 
			
		||||
    })
 | 
			
		||||
    default <P extends IPage<TestDemoVo>> P selectVoPage(IPage<TestDemo> page, Wrapper<TestDemo> wrapper) {
 | 
			
		||||
        return selectVoPage(page, wrapper, this.currentVoClass());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @DataPermission({
 | 
			
		||||
        @DataColumn(key = "deptName", value = "dept_id"),
 | 
			
		||||
        @DataColumn(key = "userName", value = "user_id")
 | 
			
		||||
    })
 | 
			
		||||
    default List<TestDemoVo> selectVoList(Wrapper<TestDemo> wrapper) {
 | 
			
		||||
        return selectVoList(wrapper, this.currentVoClass());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @DataPermission(value = {
 | 
			
		||||
        @DataColumn(key = "deptName", value = "dept_id"),
 | 
			
		||||
        @DataColumn(key = "userName", value = "user_id")
 | 
			
		||||
    }, joinStr = "AND")
 | 
			
		||||
    List<TestDemo> selectByIds(@Param(Constants.COLL) Collection<? extends Serializable> idList);
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @DataPermission({
 | 
			
		||||
        @DataColumn(key = "deptName", value = "dept_id"),
 | 
			
		||||
        @DataColumn(key = "userName", value = "user_id")
 | 
			
		||||
    })
 | 
			
		||||
    int updateById(@Param(Constants.ENTITY) TestDemo entity);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,21 @@
 | 
			
		||||
package org.dromara.demo.mapper;
 | 
			
		||||
 | 
			
		||||
import org.dromara.common.mybatis.annotation.DataColumn;
 | 
			
		||||
import org.dromara.common.mybatis.annotation.DataPermission;
 | 
			
		||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 | 
			
		||||
import org.dromara.demo.domain.TestTree;
 | 
			
		||||
import org.dromara.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<TestTree, TestTreeVo> {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1 @@
 | 
			
		||||
package org.dromara.demo.mapper;
 | 
			
		||||
@ -0,0 +1,18 @@
 | 
			
		||||
package org.dromara.demo.service;
 | 
			
		||||
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 导出下拉框Excel示例
 | 
			
		||||
 *
 | 
			
		||||
 * @author Emil.Zhang
 | 
			
		||||
 */
 | 
			
		||||
public interface IExportExcelService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 导出下拉框
 | 
			
		||||
     *
 | 
			
		||||
     * @param response /
 | 
			
		||||
     */
 | 
			
		||||
    void exportWithOptions(HttpServletResponse response);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,71 @@
 | 
			
		||||
package org.dromara.demo.service;
 | 
			
		||||
 | 
			
		||||
import org.dromara.common.mybatis.core.page.PageQuery;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
 | 
			
		||||
import org.dromara.demo.domain.TestDemo;
 | 
			
		||||
import org.dromara.demo.domain.bo.TestDemoBo;
 | 
			
		||||
import org.dromara.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);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,52 @@
 | 
			
		||||
package org.dromara.demo.service;
 | 
			
		||||
 | 
			
		||||
import org.dromara.demo.domain.bo.TestTreeBo;
 | 
			
		||||
import org.dromara.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);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,236 @@
 | 
			
		||||
package org.dromara.demo.service.impl;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.util.RandomUtil;
 | 
			
		||||
import cn.hutool.core.util.StrUtil;
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.dromara.common.core.constant.SystemConstants;
 | 
			
		||||
import org.dromara.common.core.utils.StreamUtils;
 | 
			
		||||
import org.dromara.common.excel.core.DropDownOptions;
 | 
			
		||||
import org.dromara.common.excel.utils.ExcelUtil;
 | 
			
		||||
import org.dromara.demo.domain.vo.ExportDemoVo;
 | 
			
		||||
import org.dromara.demo.service.IExportExcelService;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
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(SystemConstants.NORMAL);
 | 
			
		||||
            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, "P100000"));
 | 
			
		||||
        provinceList.add(new DemoCityData(1, null, "P200000"));
 | 
			
		||||
        provinceList.add(new DemoCityData(2, null, "P300000"));
 | 
			
		||||
 | 
			
		||||
        return provinceList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 模拟查找数据库操作,需要连带查询出省的数据
 | 
			
		||||
     *
 | 
			
		||||
     * @param provinceList 模拟的父省数据
 | 
			
		||||
     * @return /
 | 
			
		||||
     */
 | 
			
		||||
    private List<DemoCityData> getCityList(List<DemoCityData> provinceList) {
 | 
			
		||||
        List<DemoCityData> cityList = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        // 实际业务中一般采用数据库读取的形式,这里直接拼接创建
 | 
			
		||||
        cityList.add(new DemoCityData(0, 0, "C110000"));
 | 
			
		||||
        cityList.add(new DemoCityData(1, 0, "C120000"));
 | 
			
		||||
        cityList.add(new DemoCityData(2, 1, "C210000"));
 | 
			
		||||
        cityList.add(new DemoCityData(3, 1, "C220000"));
 | 
			
		||||
        cityList.add(new DemoCityData(4, 1, "C230000"));
 | 
			
		||||
 | 
			
		||||
        selectParentData(provinceList, cityList);
 | 
			
		||||
 | 
			
		||||
        return cityList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 模拟查找数据库操作,需要连带查询出市的数据
 | 
			
		||||
     *
 | 
			
		||||
     * @param cityList 模拟的父市数据
 | 
			
		||||
     * @return /
 | 
			
		||||
     */
 | 
			
		||||
    private List<DemoCityData> getAreaList(List<DemoCityData> cityList) {
 | 
			
		||||
        List<DemoCityData> areaList = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        int minCount = 500;
 | 
			
		||||
        int maxCount = 10000;
 | 
			
		||||
 | 
			
		||||
        // 实际业务中一般采用数据库读取的形式,这里直接拼接创建
 | 
			
		||||
        for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
 | 
			
		||||
            areaList.add(new DemoCityData(areaList.size(), 0, String.format("A11%04d", i)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
 | 
			
		||||
            areaList.add(new DemoCityData(areaList.size(), 1, String.format("A12%04d", i)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
 | 
			
		||||
            areaList.add(new DemoCityData(areaList.size(), 2, String.format("A21%04d", i)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
 | 
			
		||||
            areaList.add(new DemoCityData(areaList.size(), 3, String.format("A22%04d", i)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
 | 
			
		||||
            areaList.add(new DemoCityData(areaList.size(), 4, String.format("A23%04d", i)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,116 @@
 | 
			
		||||
package org.dromara.demo.service.impl;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 | 
			
		||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.dromara.common.core.exception.ServiceException;
 | 
			
		||||
import org.dromara.common.core.utils.MapstructUtils;
 | 
			
		||||
import org.dromara.common.core.utils.StringUtils;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.PageQuery;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
 | 
			
		||||
import org.dromara.demo.domain.TestDemo;
 | 
			
		||||
import org.dromara.demo.domain.bo.TestDemoBo;
 | 
			
		||||
import org.dromara.demo.domain.vo.TestDemoVo;
 | 
			
		||||
import org.dromara.demo.mapper.TestDemoMapper;
 | 
			
		||||
import org.dromara.demo.service.ITestDemoService;
 | 
			
		||||
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"));
 | 
			
		||||
        lqw.orderByAsc(TestDemo::getId);
 | 
			
		||||
        return lqw;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Boolean insertByBo(TestDemoBo bo) {
 | 
			
		||||
        TestDemo add = MapstructUtils.convert(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 = MapstructUtils.convert(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) {
 | 
			
		||||
            // 做一些业务上的校验,判断是否需要校验
 | 
			
		||||
            List<TestDemo> list = baseMapper.selectByIds(ids);
 | 
			
		||||
            if (list.size() != ids.size()) {
 | 
			
		||||
                throw new ServiceException("您没有删除权限!");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return baseMapper.deleteByIds(ids) > 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Boolean saveBatch(List<TestDemo> list) {
 | 
			
		||||
        return baseMapper.insertBatch(list);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,88 @@
 | 
			
		||||
package org.dromara.demo.service.impl;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 | 
			
		||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 | 
			
		||||
import org.dromara.common.core.utils.MapstructUtils;
 | 
			
		||||
import org.dromara.common.core.utils.StringUtils;
 | 
			
		||||
import org.dromara.demo.domain.TestTree;
 | 
			
		||||
import org.dromara.demo.domain.bo.TestTreeBo;
 | 
			
		||||
import org.dromara.demo.domain.vo.TestTreeVo;
 | 
			
		||||
import org.dromara.demo.mapper.TestTreeMapper;
 | 
			
		||||
import org.dromara.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"));
 | 
			
		||||
        lqw.orderByAsc(TestTree::getId);
 | 
			
		||||
        return lqw;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Boolean insertByBo(TestTreeBo bo) {
 | 
			
		||||
        TestTree add = MapstructUtils.convert(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 = MapstructUtils.convert(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.deleteByIds(ids) > 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1 @@
 | 
			
		||||
package org.dromara.demo.service.impl;
 | 
			
		||||
@ -0,0 +1 @@
 | 
			
		||||
package org.dromara.demo.service;
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
<?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="org.dromara.demo.mapper.TestDemoMapper">
 | 
			
		||||
 | 
			
		||||
    <select id="customPageList" resultType="org.dromara.demo.domain.vo.TestDemoVo">
 | 
			
		||||
        SELECT * FROM test_demo ${ew.customSqlSegment}
 | 
			
		||||
    </select>
 | 
			
		||||
 | 
			
		||||
</mapper>
 | 
			
		||||
@ -0,0 +1,7 @@
 | 
			
		||||
<?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="org.dromara.demo.mapper.TestTreeMapper">
 | 
			
		||||
 | 
			
		||||
</mapper>
 | 
			
		||||
@ -0,0 +1,3 @@
 | 
			
		||||
java包使用 `.` 分割 resource 目录使用 `/` 分割
 | 
			
		||||
<br>
 | 
			
		||||
此文件目的 防止文件夹粘连找不到 `xml` 文件
 | 
			
		||||
		Reference in New Issue
	
	Block a user