首页
留言
关于
友链
更多
足迹
实验室
地图组件
Search
1
SpringMVC+Spring+MyBatis整合完整版Web实例(附数据)
2,628 阅读
2
关于在Flutter实现Google地图的方法
1,042 阅读
3
SqlServer分组排序后取第一条记录
709 阅读
4
Maven仓库报错:Could not transfer artifact org.springframework.boot:spring-boot-maven-plugin:pom···
623 阅读
5
druid报异常 “sql injection violation, part alway true condition not allow”的解决方案
531 阅读
发现
技术
生活
户外
登录
Search
标签搜索
Git
JavaScript
Oracle
Git学习
Java
Flutter
MySQL
SQL Server
Spring Boot
对称加密算法
IntelliJ IDEA
Google地图
Maven
ES6
秦岭户外
Flutter 2.0
linux
Tomcat
Redis
Spring
Bai Keyang
累计撰写
269
篇文章
累计收到
275
条评论
首页
栏目
发现
技术
生活
户外
页面
留言
关于
友链
足迹
搜索到
215
篇与
技术
的结果
2021-12-15
使用WebView出现net::ERR_CLEARTEXT_NOT_PERMITTED
开发应用时(在Android11.0【Android API 30】环境下)使用Webview插件加载页面出现如下图情况: 用模拟器尝试了下其他几个版本,发现8.0版本以下的都是可以正常显示网页的,于是上网查了下原因是说从Android9.0(也就是API 28)开始,默认情况下禁用明文支持。所以url无法在webview中加载。解决办法就是在AndroidManifest中application节点内添加android:usesCleartextTraffic="true",如下:<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.baikeyang.blog"> <application android:label="blog" android:icon="@mipmap/ic_launcher" android:usesCleartextTraffic="true"> ...... </application> </manifest> 添加完成该项配置后,重启运行项目,网页就会正常显示,如下: 如果添加完配置刷新没有效果,clean一下项目,然后重新启动运行就可以了。
2021年12月15日
125 阅读
0 评论
0 点赞
2021-12-08
Flutter 2.0空安全之自定义Widge适配
自定义Widget的空安全适配分两种情况:Widget的空安全适配State的空安全适配Widget的空安全适配对于自定的Widget无论是页面的某控件还是整个页面,通常都会为Widget定义一些属性。在进行空安全适配时要对属性进行一下分类:可空的属性:通过?进行修饰不可空的属性:在构造函数中设置默认值或者通过 required 进行修饰class WebView extends StatefulWidget { String? url; final String? statusBarColor; final String? title; final bool? hideAppBar; final bool backForbid; WebView( {this.url, this.statusBarColor, this.title, this.hideAppBar, this.backForbid = false}) ...上述示例是WebView模块进行空安全适配后的效果。提示:如果构造方法中使用了 @required 那么需要改成 required 。State的空安全适配State的空安全适配主要是根据它的成员变量是否可空进行分类:可空的变量:通过 ? 进行修饰不可空的变量:可采用以下两种方式进行适配:定义时初始化;使用 late 修饰为延时变量下面是项目中的State适配了空安全后的主要代码效果可以参考下:class _TravelPageState extends State<TravelPage> with TickerProviderStateMixin { late TabController _controller; //延时初始 List<TravelTab> tabs = []; //定义时初始化 ... @override void initState() { super.initState(); _controller = TabController(length: 0, vsync: this); ...
2021年12月08日
73 阅读
0 评论
0 点赞
2021-12-06
Flutter 2.0空安全之手动关闭/开启
Flutter 2默认启用了空安全,所以通过Flutter 2创建的项目是已经开启了空安全的检查的,另外,也可以可以通过下面命令来查看你的Flutter SDK版本:flutter doctor那么,如何手动开启和关闭空区安全的?environment: sdk: ">=2.12.0 <3.0.0" //sdk >=2.12.0表示开启空安全检查提示:一旦项目开启了空安全检查,那么你的代码包括项目所依赖的三方插件必须是要支持空安全的否则是无法正常编译的。开启空安全之后,然后运行下项目你会看到很多的报错,然后定位到报错的文件,对项目进行空安全适配。如果想关闭空安全检查,可以将SDK的支持范围调整到2.12.0以下即可,如:environment: sdk: ">=2.7.0 <3.0.0"
2021年12月06日
38 阅读
0 评论
0 点赞
2021-12-05
Flutter 2.0空安全之最小必备知识
Flutter 2.0空安全之最小必备知识从Flutter 2开始,Flutter便在配置中默认启用了空安全,通过将空检查合并到类型系统中,可以在开发过程中捕获这些错误,从而防止再生产环境导致的崩溃。{dotted startColor="#ff6c6c" endColor="#1989fa"/}什么是空安全时至今日,空安全已经是一个屡见不鲜的话题,目前像主流的编程语言Kotlin、Swift、Rust 等都对空安全有自己的支持。Dart从2.12版本开始支持了空安全,通过空安全开发人员可以有效避免null错误崩溃。空安全性可以说是Dart语言的重要补充,它通过区分可空类型和非可空类型进一步增强了类型系统。引入空安全的好处可以将原本运行时的空值引用错误将变为编辑时的分析错误;增强程序的健壮性,有效避免由Null而导致的崩溃;跟随Dart和Flutter的发展趋势,为程序的后续迭代不留坑;空安全最小必备知识空安全的原则引入空安全前后Dart类型系统的变化可空(?)类型的使用延迟初始化(late)的使用空值断言操作符(!)的使用空安全的原则Dart 的空安全支持基于以下三条核心原则:默认不可空:除非您将变量显式声明为可空,否则它一定是非空的类型;渐进迁移:您可以自由地选择何时进行迁移,多少代码会进行迁移;完全可靠:Dart 的空安全是非常可靠的,意味着编译期间包含了很多优化,如果类型系统推断出某个变量不为空,那么它 永远 不为空。当您将整个项目和其依赖完全迁移至空安全后,您会享有健全性带来的所有优势——更少的 BUG、更小的二进制文件以及更快的执行速度。引入空安全前后Dart类型系统的变化在引入空安全前Dart的类型系统是这样的: 这意味着在之前,所有的类型都可以为Null,也就是Nul类型被看作是所有类型的子类。在引入空安全之后: 可以看出,最大的变化是将Null类型独立出来了, 这意味着Null不在是其它类型的子类型,所以对于一个非Null类型的变量传递一个Null值时会报类型转换错误 。提示:在使用了空安全的Flutter或Dart项目中你会经常看到 ?.、!、late 的大量应用,那么他们分别是什么又改如何使用呢?请看下文的分析可空(?)类型的使用我们可以通过将 ? 跟在类型的后面来表示它后面的变量或参数可接受Null:class CommonModel { String? firstName; //可空的成员变量 int getNameLen(String? lastName /*可空的参数*/) { int firstLen = firstName?.length ?? 0; int lastLen = lastName?.length ?? 0; return firstLen + lastLen; } }对于可空的变量或参数在使用的时候需要通过Dart 的避空运算符 ?. 来进行访问,否则会抛出编译错误。当程序启用空安全后,类的成员变量默认是不可空的,所以对于一个非空的成员变量需要指定其初始化方式class CommonModel { List names=[];//定义时初始化 final List colors;//在构造方法中初始化 late List urls;//延时初始化 CommonModel(this.colors); ...延迟初始化(late)的使用对于无法在定义时进行初始化,并且又想避免使用 ?. ,那么延迟初始化可以帮到你。通过 late 修饰的变量,可以让开发者选择初始化的时机,并且在使用这个变量时可以不用 ?. 。 late List urls;//延时初始化 setUrls(List urls){ this.urls=urls; } int getUrlLen(){ return urls.length; }延时初始化虽然能为我们编码带来一定便利,但如果使用不当会带来空异常的问题,所以在使用的时候一定保证赋值和访问的顺序,切莫颠倒。扩展: 延迟初始化(late)使用范式在Flutter中State的 initState 方法中初始化的一些变量是比较适合使用late来进行延时初始化的,因为在Widget生命周期中 initState 方法是最先执行的,所以它里面初始化的变量通过 late 修饰后既能保障使用时的便利,又能防止空异常,下面就来看下具体的用法:class _SpeakPageState extends State<SpeakPage> with SingleTickerProviderStateMixin { String speakTips = '长按说话'; String speakResult = ''; late Animation<double> animation; late AnimationController controller; @override void initState() { controller = AnimationController( super.initState(); vsync: this, duration: Duration(milliseconds: 1000)); animation = CurvedAnimation(parent: controller, curve: Curves.easeIn) ..addStatusListener((status) { if (status == AnimationStatus.completed) { controller.reverse(); } else if (status == AnimationStatus.dismissed) { controller.forward(); } }); } ...空值断言操作符(!)的使用当我们排除变量或参数的可空的可能后,可以通过 ! 来告诉编译器这个可空的变量或参数不可空,这对我们进行方法传参或将可空参数传递给一个不可空的入参时特别有用: Widget get _listView { return ListView( children: <Widget>[ _banner, Padding( padding: EdgeInsets.fromLTRB(7, 4, 7, 4), child: LocalNav(localNavList: localNavList), ), if (gridNavModel != null) Padding( padding: EdgeInsets.fromLTRB(7, 0, 7, 4), child: GridNav(gridNavModel: gridNavModel!)), Padding( padding: EdgeInsets.fromLTRB(7, 0, 7, 4), child: SubNav(subNavList: subNavList)), if (salesBoxModel != null) Padding( padding: EdgeInsets.fromLTRB(7, 0, 7, 4), child: SalesBox(salesBox: salesBoxModel!)), ], ); }上述代码是根据gridNavModel与salesBoxModel模块数据是否为空时动态创建的列表,在确保变量不为空的情况下使用了空值断言操作符!。除此之外, ! 还有一个常见的用处:bool isEmptyList(Object object) { if (object is! List) return false; return object.isEmpty; }用在这里表示取反,上述代码等价于:bool isEmptyList(Object object) { if (!(object is List)) return false; return object.isEmpty; }
2021年12月05日
50 阅读
0 评论
0 点赞
2021-12-02
SpringBoot手动控制启动定时任务
在SpringBoot中启动定时任务只需要添加注解 @EnableScheduling 即可搞定,package cn.org.kcis; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling public class StartApplication { public static void main(String[] args) { SpringApplication.run(StartApplication.class, args); } } 然后再Job类上面添加 @Component 和 @Scheduled在任务的类上写@Component在任务方法上写@Scheduledpackage cn.org.kcis.xian.task; import cn.org.kcis.xian.controller.IndexController; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.stereotype.Component; import org.springframework.scheduling.annotation.Scheduled; /** * @Author : BaiKeyang * @Date : Created in 2020/7/16 11:27 * @Description: * @Modified By: * @Version: $ */ @Component public class ScheduledService { private static final Logger log = LogManager.getLogger(IndexController.class); // 表示每隔1小时执行 @Scheduled(cron = "0 0 */1 * * ?") public void test1(){ log.error("=====>>>>>test1 {}",System.currentTimeMillis()); } // 表示每隔3分钟执行 @Scheduled(cron = "0 */3 * * * ?") public void test2(){ log.error("=====>>>>>test2 {}",System.currentTimeMillis()); } // 表示每天15分、45分 执行 @Scheduled(cron = "0 15/30 * * * ?") public void test3(){ log.error("=====>>>>>test3 {}",System.currentTimeMillis()); } // 每天的上午8点到20点执行 @Scheduled(cron = "0 0 8-20 * * ?") public void test6(){ log.error("=====>>>>>test6 {}",System.currentTimeMillis()); } // 表示每天8点30分执行 @Scheduled(cron = "0 0,30 0,8 ? * ? ") public void test7() { log.error("=====>>>>>test7 {}",System.currentTimeMillis()); } // 表示每天凌晨1点执行 @Scheduled(cron = "0 0 1 * * ?") public void test8() { log.error("=====>>>>>test8 {}",System.currentTimeMillis()); } // 表示每隔3秒 @Scheduled(fixedRate = 3000) public void test4() { log.info("=====>>>>>test4{}", System.currentTimeMillis()); } // 表示方法执行完成后5秒 @Scheduled(fixedDelay = 5000) public void test5() { log.info("=====>>>>>test5{}",System.currentTimeMillis()); } } 启动项目后,注解的方法都会根据配置的cron表达式、fixedDelay和fixedRate 参数值去开始运行。如果需要手动的去启动定时任务,再在上面定义实现了ThreadPoolTaskScheduler的实例:package cn.org.kcis; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @SpringBootApplication @EnableScheduling public class StartApplication { public static void main(String[] args) { SpringApplication.run(StartApplication.class, args); } @Bean public ThreadPoolTaskScheduler threadPoolTaskScheduler () { return new ThreadPoolTaskScheduler(); } } 创建任务类,注入 ThreadPoolTaskScheduler ,通过 threadPoolTaskScheduler.schedule() 来创建、启动定时任务,并将任务保存,以便于下次关闭;package cn.org.kcis.xian.task; import cn.hutool.core.util.StrUtil; import cn.org.kcis.xian.controller.IndexController; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.support.CronTrigger; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ScheduledFuture; /** * @Author : BaiKeyang * @Date : Created in 2020/7/16 11:27 * @Description: * @Modified By: * @Version: $ */ @Component public class ScheduledService { private static final Logger log = LogManager.getLogger(IndexController.class); @Autowired ThreadPoolTaskScheduler threadPoolTaskScheduler; Map<String, ScheduledFuture<?>> futureMap; public void start (String key) { if(StrUtil.isNotEmpty(key)) { if(futureMap == null){ futureMap = new HashMap<>(); } if("test".equals(key)) { ScheduledFuture<?> future1 = threadPoolTaskScheduler.schedule(new myTask1(), new CronTrigger("0/1 * * * * ?")); futureMap.put("task1", future1); } else if("server".equals(key)) { ScheduledFuture<?> future2 = threadPoolTaskScheduler.schedule(new myTask2(), new CronTrigger("0 */3 * * * ?")); futureMap.put("task2", future2); } else if("ps".equals(key)) { ScheduledFuture<?> future2 = threadPoolTaskScheduler.schedule(new myTask3(), new CronTrigger("0 */1 * * * ?")); futureMap.put("task3", future2); } } } // 关闭指定的定时任务 public String stop (String key) { if(futureMap != null && StrUtil.isNotEmpty(key) && futureMap.get(key) != null) { futureMap.get(key).cancel(true); } System.out.println("定时任务已关闭"); return "定时任务已关闭"; } private class myTask1 implements Runnable { @Override public void run() { System.out.println("test" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); } } private class myTask2 implements Runnable { @Override public void run() { log.error("=====>>>>>服务可用性扫描 {}",System.currentTimeMillis()); } } private class myTask3 implements Runnable { @Override public void run() { log.error("=====>>>>>数据同步 {}",System.currentTimeMillis()); } } } 在外部通过Controller调用来实现手动开启/关闭某个任务的操作:package cn.org.kcis.xian.controller; import cn.org.kcis.xian.task.ScheduledService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @Author : BaiKeyang * @Date : Created in 2020/2/4 17:37 * @Description: * @Modified By: * @Version: $ */ @RestController(value = "demoController") public class HelloController { @Autowired ScheduledService scheduledService; @RequestMapping(value = "/run") public String run(String key) { scheduledService.start(key); return "定时任务已启动"; } @RequestMapping(value = "/stop") public String stop(String key) { scheduledService.stop(key); return "定时任务已关闭"; } } 通过上面的方式,这样就实现了SpringBoot中手动控制定时任务的效果了。
2021年12月02日
114 阅读
0 评论
0 点赞
2021-11-28
Flutter 音频播放
在Flutter中目前使用比较多的音频插件就是audioplayers啦。 插件地址:audioplayers 在项目的pubspec.yaml中引入audioplayers插件:dependencies: flutter: sdk: flutter ...... # 引入audioplayers插件:当前官方最新版本为0.20.1 audioplayers: ^0.20.1初始化AudioPlayer :AudioPlayer player = new AudioPlayer ();开始播放 :开始播放音频player.play('http://image.bkybk.com/bg.m4a');暂停播放 :音频播放对象在播放状态才能暂停,在其它状态调用此方法无任何作用player.pause();继续播放 :音频播放对象在暂停状态才能恢复播放,在其它状态调用此方法无任何作用。player.resume();停止播放 :停止播放音频,音频播放对象在播放或暂停状态才能停止播放,在其它状态调用此方法无任何作用。停止播放后如果需要继续播放,则需调用play方法重新开始播放。// 方法1 player.stop(); // 方法2 player.setReleaseMode(ReleaseMode.STOP); player.release();指定播放位置 :跳到指定位置播放音频// 从音频的 96 秒开始播放 player.seek(new Duration(milliseconds: 96000))设置音量 :设置播放音量的大小// 设置音量 30 player.setVolume(0.3)上面是关于AudioPlayer在项目中常用的声明、方法和配置,下面是关于AudioPlayer插件的具体使用:// 引入包 import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; class AudioPage extends StatefulWidget { @override _AudioPageState createState() => _AudioPageState(); } class _AudioPageState extends State<AudioPage> { String totalTime = ''; String goTime = ''; String playState = ''; double _sliderValue = 30; bool isPlay = false; // 音频列表 List _playList = [ 'http://bkybk.com/static/data/bg.mp3', 'http://image.bkybk.com/bg.m4a' ]; // 初始化AudioPlayer AudioPlayer advancedPlayer = AudioPlayer(); @override void initState() { // TODO: implement initState print('------------initState---------------'); super.initState(); advancedPlayer.onDurationChanged.listen((Duration d) { setState(() { totalTime = d.toString(); playState = '正在播放'; }); }); advancedPlayer.onPlayerCompletion.listen((event) { setState(() { playState = '播放已完成'; }); }); advancedPlayer.onAudioPositionChanged.listen((p) async { // p参数可以获取当前进度,也是可以调整的,比如p.inMilliseconds setState(() { goTime = p.toString(); }); }); // 代码中引发意外错误时调用此函数。 advancedPlayer.onPlayerError.listen((msg) { print('audioPlayer error : $msg'); // setState(() { // playerState = PlayerState.stopped; // duration = Duration(seconds: 0); // position = Duration(seconds: 0); // }); }); } /// 当依赖的State对象改变时会调用 /// a 在第一次构建widget时,在initState()之后立即调用此方法 /// b 如果StatefulWidget依赖于InheritedWidget,那么当 当前的State所依赖InheritedWidget中的变量改变时会再次调用它 /// 拓展:InheritedWidget可以高效的将数据在Widget树中向下传递、共享; @override void didChangeDependencies() { print('--------------didChangeDependencies--------------'); super.didChangeDependencies(); } @override void dispose() { // TODO: implement dispose super.dispose(); advancedPlayer.stop(); advancedPlayer.dispose(); } @override Widget build(BuildContext context) { String? localFilePath; String? localAudioCacheURI; return new Scaffold( appBar: AppBar( title: Text('Audio 组件演示'), leading: GestureDetector( onTap: () { Navigator.pop(context); }, child: Icon(Icons.arrow_back), ), ), body: Container( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: ListView( children: [ ElevatedButton( onPressed: () => play(advancedPlayer, 0), child: Text('播放音乐1')), ElevatedButton( onPressed: () => play(advancedPlayer, 1), child: Text('播放音乐2')), ElevatedButton( onPressed: () => pause(advancedPlayer), child: Text('暂停')), ElevatedButton( onPressed: () => stop(advancedPlayer), child: Text('停止')), ElevatedButton( onPressed: () => skip(advancedPlayer, 96300), child: Text('从96秒播放')), ElevatedButton( onPressed: () => resume(advancedPlayer), child: Text('继续播放')), Text('音频总长:$totalTime'), Text('当前播放:$goTime'), Text('播放状态:$playState'), Text('调整音量:'), Slider( min: 0, max: 100, value: _sliderValue, onChanged: (v) { setState(() { _sliderValue = v; }); setVolume(advancedPlayer, v); }, ), ElevatedButton( onPressed: () { countFunction(advancedPlayer); }, child: Text('其他常用(控制台输出)')) ], ), ) ], ), ), ); } countFunction(AudioPlayer audioPlayer) { setState(() { _count++; }); // 获取当前播放状态 PlayerState ps = audioPlayer.state; print(ps); // 判断目标是否为本地资源 bool isLocal = audioPlayer.isLocalUrl("http://image.bkybk.com/bg.m4a"); print(isLocal); // 设置音量 audioPlayer.setVolume(0.23); } /** * 设置音量 */ setVolume(AudioPlayer audioPlayer, double value) { audioPlayer.setVolume(value / 100); } /** * 开始播放音频 */ play(AudioPlayer audioPlayer, int index) async { if (isPlay) { // 当音乐正在播放时,先停止当前播放; int stopResult = await audioPlayer.stop(); if (stopResult == 1) { isPlay = false; int playResult = await audioPlayer.play(_playList[index], volume: 0.3); if (playResult == 1) { // success print('play success'); setState(() { isPlay = true; playState = '正在加载资源......'; }); } else { print('play failed'); } } } else { int playResult = await audioPlayer.play(_playList[index], volume: 0.3); if (playResult == 1) { // success print('play success'); setState(() { isPlay = true; playState = '正在加载资源......'; }); } else { print('play failed'); } } } /** * 暂停播放音频 */ pause(AudioPlayer audioPlayer) async { // 音频播放对象在播放状态才能暂停,在其它状态调用此方法无任何作用 int result = await audioPlayer.pause(); if (result == 1) { // success print('pause success'); setState(() { isPlay = false; playState = '播放暂停'; }); } else { print('pause failed'); } } /** * 停止播放音频 */ stop(AudioPlayer audioPlayer) async { // 停止播放音频,音频播放对象在播放或暂停状态才能停止播放,在其它状态调用此方法无任何作用。 // 停止播放后如果需要继续播放,则需调用play方法重新开始播放。 // 停止播放的方法一: int stopResult = await audioPlayer.stop(); // 停止播放的方法二: // audioPlayer.setReleaseMode(ReleaseMode.STOP); // int stopResult = await audioPlayer.release(); if (stopResult == 1) { setState(() { isPlay = false; playState = '播放停止'; }); } else { print('release failed'); } super.deactivate(); } /** * 跳到指定位置播放音频 */ skip(AudioPlayer audioPlayer, int startMilliseconds) async { // 跳到指定位置播放音频,音频播放对象在播放或暂停状态才能跳到指定播放音频,在其它状态调用此方法无任何作用。 int result = await audioPlayer.seek(new Duration(milliseconds: startMilliseconds)); if (result == 1) { print('go to success'); // await audioPlayer.resume(); } else { print('go to failed'); } } /** * 恢复播放音频 */ resume(AudioPlayer audioPlayer) async { // 音频播放对象在暂停状态才能恢复播放,在其它状态调用此方法无任何作用。 int result = await audioPlayer.resume(); if (result == 1) { print('resume success'); // await audioPlayer.resume(); } else { print('resume failed'); } } } 代码的实际运行效果:
2021年11月28日
134 阅读
0 评论
0 点赞
1
2
3
...
36