依桐博客
type: channel
link: https://www.jufb.cn/
description: 依桐博客是一个网络资源分享平台，建站初衷是为了提供一个舒心、有爱的交流环境，希望各位都能感受到「家」的温暖！
items: Java模板占位符解析器工具 PlaceholderHelper
items: 域名ICP备案批量查询PHP源码
items: postgreSql使用on conflict语法新增或更新保存最后一次数据
items: Java使用qrcode-plugin生成个性二维码
items: JS复制Base64图片到黏贴版代码
items: SpringBoot整合XXL-JOB分布式任务调度平台
items: Java Stream流 一些开发中的常见实用用法
items: Java获取处理日期的一些常用类方法
items: SpringBoot使用自定义注解实现AOP记录用户日志功能
items: SpringBoot拦截器中@Value读取yml文件无效的解决办法

Java模板占位符解析器工具 PlaceholderHelper
type: item
date: 2023-05-02T00:09:00+08:00
description: 介绍当我们有个固定的模板，但是里面某些值不一样，可以使用该工具类将里面的变量进行替换！使用案例对象传递 （支持取子类或父类）User user = new User(); user.setName("依桐"); user.setAge(21); User.Detail detail = new User.Detail(); user.setDetail(detail); User.Detail.Ability ability = new User.Detail.Ability(); ability.setHobbyList(new ArrayList<String>() {{ add("Java"); }}); detail.setAbility(ability); String contentByObj = "我是${user.name} ,今年${user.age}岁, 我的爱好：${user.detail.ability.hobbyList}"; String result = PlaceholderHelper.resolve(contentByObj, user); //输出内容：我是依桐 ,今年21岁, 我的爱好：[Java] System.out.println(result); Map传递（支持取多维Map/对象）User user = new User(); user.setName("依桐 - 对象"); user.setAge(21); User.Detail detail = new User.Detail(); detail.setPhone("123456789"); user.setDetail(detail); User.Detail.Ability ability = new User.Detail.Ability(); ability.setHobbyList(new ArrayList<String>() {{ add("Java"); }}); detail.setAbility(ability); Map<String, Object> valueMap = new HashMap<>(); valueMap.put("name", "依桐"); valueMap.put("age", 21); valueMap.put("user", user); String contentByMap = "我是${name} ,今年${age}岁, 我的爱好：${user.detail.ability.hobbyList}"; String result = PlaceholderHelper.resolve(contentByMap, valueMap); //输出内容：我是依桐 ,今年21岁, 我的爱好：[Java] System.out.println(result); PlaceholderHelper 占位符解析器工具代码/** * 占位符解析器 * * @author www.jufb.cn */ public class PlaceholderHelper { /** * 默认前缀占位符 */ public static final String DEFAULT_PLACEHOLDER_PREFIX = "${"; /** * 默认后缀占位符 */ public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}"; /** * 占位符前缀长度 */ public static final int PREFIX_LENGTH = DEFAULT_PLACEHOLDER_PREFIX.length(); /** * 占位符后缀长度 */ public static final int SUFFIX_LENGTH = DEFAULT_PLACEHOLDER_SUFFIX.length(); /** * 根据map解析占位符 * * @param content 内容 * @param valueMap map * @return 解析后的内容 */ public static String resolve(String content, Map<String, Object> valueMap) { return resolveByRule(content, placeholder -> { String[] fieldNames = placeholder.split("\\."); //如果是多级占位符 如：user.name 那么可能是map中的key，也可能是对象中的属性 优先取map中的key 如果没有则取对象中的属性 if…

域名ICP备案批量查询PHP源码
type: item
date: 2023-03-10T23:56:00+08:00
description: 源码介绍可以批量检测域名是否备案，如果有符合条件的域名，那么则会返回域名的ICP备案信息接口调用截图源码解析该接口的实现方法：通过curl模拟访问站长之家的查询页面，通过正则获取关键信息使用介绍单个PHP文件，直接上传到服务器就可以使用了，无需数据库！接口地址(例)：localhost/icp.php?domainList=jufb.cn,baidu.com参数详情：支持单个或批量查询，如有多个域名以,隔开，单次最大支持20个源码下载地址：https://ycm.lanzouy.com/iYFiY0pss77g

postgreSql使用on conflict语法新增或更新保存最后一次数据
type: item
date: 2023-03-05T23:28:00+08:00
description: 业务场景任务计划会每隔一段时间去检测设备的状态保存到A表，我们需要保存设备最后一次的检测状态到B表SQL数据表示例首先我们有两张表，一张是device_last_status（用于存储设备最后一次检测状态），另一张是device_plan（用于存储每次计划的检测记录）SQL语句insert into device_last_status (device_id, online, real_video) select device_id, online, real_video from device_plan as p where "planId" = '1' on conflict (device_id) do update set (device_id, online, real_video) = ( EXCLUDED.device_id, EXCLUDED.online, EXCLUDED.real_video ) 语法解释conflict里的字段必须为主键或者唯一索引，可以多个字段作为唯一索引，在数据库设置唯一，不然会报 "there is no unique or exclusion constraint matching the ON CONFLICT specification"错误插入和更新并不是批量数据一一对应操作的 而是批量insert然后再判断是否更新 所以下面只能写死一条数据 多了就报错pgsql在这种情况下会提供一个EXCLUDED临时表把之前插入的值储存起来

Java使用qrcode-plugin生成个性二维码
type: item
date: 2023-01-03T00:08:00+08:00
description: Maven导包 com.github.liuyueyi.media qrcode-plugin 3.0.0 使用样例普通二维码BufferedImage image = QrCodeGenV3.of("https://www.jufb.cn/").build().asImg();中间带LOGO的二维码BufferedImage image = QrCodeGenWrapper.of("https://www.jufb.cn/") //黑色方块变小方块 .setDrawStyle(QrCodeOptions.DrawStyle.MINI_RECT) .setDrawEnableScale(true) // 设置二维码颜色 .setDrawPreColor(new Color(203, 156, 73)) // 设置LOGO .setLogo("/image/icon.png") // 设置logo大小 .setLogoRate(8) // 设置LOGO四角样式 .setLogoStyle(QrCodeOptions.LogoStyle.NORMAL) //设置精度 .setErrorCorrection(ErrorCorrectionLevel.M) //设置二维码大小 .setW(400) //true 则探测图形有本身的绘制规则 .setDetectSpecial() .asBufferedImage();常用方法获取图片Base64public String createJumpQRCode(String url) throws Exception { BufferedImage image = QrCodeGenV3.of("https://www.jufb.cn/").build().asImg(); String QRCodeBase64Image = null; ByteArrayOutputStream os = new ByteArrayOutputStream(); try { ImageIO.write(image, “png”, os); QRCodeBase64Image = Base64.encode(os.toByteArray()); } finally { os.flush(); os.close(); } return "data:image/png;base64," + QRCodeBase64Image; } 更多详细样例https://hhui.top/quick/quick-media/qrcode/3.x二维码基本使用姿势/

JS复制Base64图片到黏贴版代码
type: item
date: 2023-01-02T23:54:00+08:00
description: 介绍需要https的支持，可将Base64或URL图片复制到黏贴版中！ /** * 复制图片，接受 data: URI 和 http[s] 的图片地址 * @param url * @returns {Promise<unknown>} */ function image2blob (url) { return new Promise(resolve => { // 如果是 data 开头的就使用 DataURI 的解析 if (url.indexOf('data:') === 0) { return resolve(new ClipboardItem({ 'image/png': dataURItoBlob(url) })) } const img = new Image const c = document.createElement('canvas') const ctx = c.getContext('2d') img.onload = function () { c.width = this.naturalWidth c.height = this.naturalHeight ctx.drawImage(this, 0, 0) c.toBlob(blob => resolve(new ClipboardItem({ 'image/png': blob })), 'image/png', 1) } img.crossOrigin = '' img.src = url }) } /** * 将 data: 开头的 dataURI base64 图片转为 blob * @param dataURI * @returns {Blob} */ function dataURItoBlob (dataURI) { var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0] // mime类型 var byteString = atob(dataURI.split(',')[1]) //base64 解码 var arrayBuffer = new ArrayBuffer(byteString.length) //创建缓冲数组 var intArray = new Uint8Array(arrayBuffer) //创建视图 for (var i = 0; i < byteString.length; i++) { intArray[i] = byteString.charCodeAt(i) } return new Blob([intArray], { type: mimeString }) } /** * 复制图片 * @param url * @returns {Promise<unknown>} */ function copyImage (url) { return new Promise((resolve, reject) => { image2blob(url).then(data => { navigator.clipboard.write([data]).then(resolve, reject) }) }) } window.onload = function () { if (!document.hasFocus()) { alert('必须窗口获得焦点') return } copyImage(...).then(() => alert('复制成功'), (e) => alert(e)) }

SpringBoot整合XXL-JOB分布式任务调度平台
type: item
date: 2022-12-25T17:16:00+08:00
description: 简介XXL-JOB是一个分布式任务调度平台，其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线，开箱即用。gitee码云地址: https://gitee.com/xuxueli0323/xxl-job部署 XXL-JOB 后台在gitee码云中下载源码后导入到IDEA中,首先将SQL文件导入到数据库中, 然后修改properties数据库连接配置, 最后直接启动即可, 启动后在浏览器地址输入: http://127.0.0.1:8080/xxl-job-admin/ 即可进入到后台管理页面, 账号:admin 密码:123456SpringBoot整合XXL-JOB1.Maven导包 com.xuxueli xxl-job-core 2.3.1 2.创建XxlJobConfig类XxlJobConfig这个类在码云下载的源码中有,直接copy过来就可以!3.在yml中配置相关参数server: port: 9001 xxl: job: accessToken: default_token admin: addresses: http://127.0.0.1:8080/xxl-job-admin executor: appname: xxl-job-executor-sample #执行期管理名称 需要与后台配置的一致 port: 9999 ip: logpath: ./data/applogs/xxl-job/jobhandler logretentiondays: 304.建立任务文件/** * demoJobHandler 每个任务都有JobHandler名称 在后台任务管理中配置 */ @XxlJob("demoJobHandler") public void demoJobHandler() { //获取任务参数 String jobParam = XxlJobHelper.getJobParam(); System.out.println("demoJobHandler 任务执行了..."); }5.进行启动测试6.执行效果

Java Stream流 一些开发中的常见实用用法
type: item
date: 2022-12-22T13:05:00+08:00
description: 首先准备一些数据字段为: 设备名称,目录名称,是否在线List集合根据设备目录分组为Map集合Map<String, List<Device>> groupByCatalogName = deviceList.stream().collect(Collectors.groupingBy(Device::getCatalogName)); 统计List集合中所有设备在线/离线数量//在线数量 long onlineCount = deviceList.stream().filter(Device::getOnline).count(); //离线数量 long offlineCount = deviceList.stream().filter(device -> !device.getOnline()).count(); 根据设备目录进行分组统计数量Map<String, Long> countGroupByCatalog = deviceList.stream().collect(Collectors.groupingBy(Device::getCatalogName, Collectors.counting())); List转Map Key=>Value形式Map<String, String> deviceMap = deviceList.stream().collect(Collectors.toMap(Device::getDeviceName, Device::getCatalogName)); List转Map 名称字段作为Key,实体类ValueMap<String, Device> deviceMap = deviceList.stream().collect(Collectors.toMap(Device::getDeviceName, account -> account));

Java获取处理日期的一些常用类方法
type: item
date: 2022-12-18T19:37:00+08:00
description: 获取当前年月日LocalDate now = LocalDate.now(); //2022-12-18 int year = LocalDate.now().getYear(); //2022 int month = LocalDate.now().getMonth().getValue(); //12 int day = LocalDate.now().getDayOfMonth(); //18 获取当前时分秒LocalTime now = LocalTime.now(); //19:21:55.125 int hour = LocalTime.now().getHour(); //19 int minute = LocalTime.now().getMinute(); //21 int second = LocalTime.now().getSecond(); //55 获取当前年-月-日 时:分:秒DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime now = LocalDateTime.now(); String nowTime = dtf.format(now); System.out.println(dateFormat); //2022-12-18 19:21:55 日期时间之间格式相互转换String nowTime = "2022-12-18 19:21:55"; Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(nowTime); String dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒").format(date); System.out.println(dateFormat); //2022年12月18日 19时21分55秒

SpringBoot使用自定义注解实现AOP记录用户日志功能
type: item
date: 2022-10-08T21:40:55+08:00
description: 问题在项目中,想记录用户的日志,如果每个方法都写一遍记录日志入库操作,那么代码肯定不优雅,我们可以通过AOP去记录日志入库操作,只需写一遍代码,通过自定义注解形式去识别哪些需要记录的日志!Maven导包 org.springframework spring-context org.aspectj aspectjweaver AOP记录日志注解代码/** * AOP记录日志 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface LogAop { String code() default ""; } 使用方式在方法上声明注解 @LogAop(code = "USER_PWD_LOGIN")AOP记录日志功能实现 /** * 切入点表达式 */ @Pointcut("execution(* cn.jufb.user.service.*.*(..))") private void pt() { } /** * 记录日志 * * @param pjp * @return * @throws Throwable */ @Around("pt()") public Object recordLog(ProceedingJoinPoint pjp) throws Throwable { //方法返回结果 Object resultData = pjp.proceed(); //获取LogAop注解中的 日志类型编码 MethodSignature methodSignature = (MethodSignature) pjp.getSignature(); Method method = methodSignature.getMethod(); LogAop logAop = method.getAnnotation(LogAop.class); if (null == logAop || StringUtils.isBlank(logAop.code())) { return resultData; } String logType = logAop.code(); //... } 效果处理方案此时我们已经拿到了,我们自定义的注解值,以上图为例: 此时拿到了USER_PWD_LOGIN这个值,我们可以进行入库或其他操作,如果想转译成中文或者是还想在库中记录详细信息,我们可以通过枚举,通过我们传过来的值进行获取其他信息等

SpringBoot拦截器中@Value读取yml文件无效的解决办法
type: item
date: 2022-10-08T21:03:00+08:00
description: 问题在开发微服务项目中,想在gatway网关header头添加密钥字段向下传递,密钥配置在了yml文件中,结果在下面服务中使用@Value获取不到yml的值,一顿百度结果发现拦截器是手动new出来的, 此时并没有交给Spring去管理, 只需重新new一个拦截器并在方法中声明@Bean交给Spring去管理,并修改addInterceptors方法中注册拦截器的方式即可效果此时通过@Value注解即可获取到响应的值