flutter系列之:做一个下载按钮的动画

目录
  • 简介
  • 定义下载的状态
  • 定义DownloadButton的属性
  • 让DownloadButton的属性可以动态变化
  • 定义downloadController
  • 定义DownloadButton的细节
  • 总结

简介

我们在app的开发过程中经常会用到一些表示进度类的动画效果,比如一个下载按钮,我们希望按钮能够动态显示下载的进度,这样可以给用户一些直观的印象,那么在flutter中一个下载按钮的动画应该如何制作呢?

一起来看看吧。

定义下载的状态

我们在真正开发下载按钮之前,首先定义几个下载的状态,因为不同的下载状态导致的按钮展示样子也是不一样的,我们用下面的一个枚举类来设置按钮的下载状态:

enum DownloadStatus {
  notDownloaded,
  fetchingDownload,
  downloading,
  downloaded,
}

基本上有4个状态,分别是没有下载,准备下载但是还没有获取到下载的资源链接,获取到下载资源正在下载中,最后是下载完毕。

定义DownloadButton的属性

这里我们需要自定义一个DownloadButton组件,这个组件肯定是一个StatelessWidget,所有的状态信息都是由外部传入的。

我们需要根据下载状态来指定DownloadButton的样式,所以需要一个status属性。下载过程中还有一个下载的进度条,所以我们需要一个downloadProgress属性。

另外在点击下载按钮的时候会触发onDownload事件,下载过程中可以触发onCancel事件,下载完毕之后可以出发onOpen事件。

最后因为是一个动画组件,所以还需要一个动画的持续时间属性transitionDuration。

所以我们的DownloadButton需要下面一些属性:

class DownloadButton extends StatelessWidget {
  ...
  const DownloadButton({
    super.key,
    required this.status,
    this.downloadProgress = 0.0,
    required this.onDownload,
    required this.onCancel,
    required this.onOpen,
    this.transitionDuration = const Duration(milliseconds: 500),
  });

让DownloadButton的属性可以动态变化

上面提到了DownloadButton是一个StatelessWidget,所有的属性都是由外部传入的,但是对于一个动画的DownloadButton来说,status,downloadProgress这些信息都是会动态变化的,那么怎么才能让变化的属性传到DownloadButton中进行组件的重绘呢?

因为涉及到复杂的状态变化,所以简单的AnimatedWidget已经满足不了我们的需求了,这里就需要用到flutter中的AnimatedBuilder组件了。

AnimatedBuilder是AnimatedWidget的子类,它有两个必须的参数,分别是animation和builder。

其中animation是一个Listenable对象,它可以是Animation,ChangeNotifier或者等。

AnimatedBuilder会通过监听animation的变动情况,来重新构建builder中的组件。buidler方法可以从animation中获取对应的变动属性。

这样我们创建一个Listenable的DownloadController对象,然后把DownloadButton用AnimatedBuilder封装起来,就可以实时监测到downloadStatus和downloadProgress的变化了。

如下所示:

Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('下载按钮')),
      body: Center(
        child: SizedBox(
          width: 96,
          child: AnimatedBuilder(
            animation: _downloadController,
            builder: (context, child) {
              return DownloadButton(
                status: _downloadController.downloadStatus,
                downloadProgress: _downloadController.progress,
                onDownload: _downloadController.startDownload,
                onCancel: _downloadController.stopDownload,
                onOpen: _downloadController.openDownload,
              );
            },
          ),
        ),
      ),
    );
  }

定义downloadController

downloadController是一个Listenable对象,这里我们让他实现ChangeNotifier接口,并且定义了两个获取下载状态和下载进度的方法,同时也定义了三个点击触发事件:

abstract class DownloadController implements ChangeNotifier  {
  DownloadStatus get downloadStatus;
  double get progress;

  void startDownload();
  void stopDownload();
  void openDownload();
}

接下来我们来实现这个抽象方法:

class MyDownloadController extends DownloadController
    with ChangeNotifier {
  MyDownloadController({
    DownloadStatus downloadStatus = DownloadStatus.notDownloaded,
    double progress = 0.0,
    required VoidCallback onOpenDownload,
  })  : _downloadStatus = downloadStatus,
        _progress = progress,
        _onOpenDownload = onOpenDownload;

startDownload,stopDownload这两个方法是跟下载状态和下载进度相关的,先看下stopDownload:

  void stopDownload() {
    if (_isDownloading) {
      _isDownloading = false;
      _downloadStatus = DownloadStatus.notDownloaded;
      _progress = 0.0;
      notifyListeners();
    }
  }

可以看到这个方法最后需要调用notifyListeners来通知AnimatedBuilder来进行组件的重绘。

startDownload方法会复杂一点,我们需要模拟下载状态的变化和进度的变化,如下所示:

  Future<void> _doDownload() async {
    _isDownloading = true;
    _downloadStatus = DownloadStatus.fetchingDownload;
    notifyListeners();

    // fetch耗时1秒钟
    await Future<void>.delayed(const Duration(seconds: 1));

    if (!_isDownloading) {
      return;
    }

    // 转换到下载的状态
    _downloadStatus = DownloadStatus.downloading;
    notifyListeners();

    const downloadProgressStops = [0.0, 0.15, 0.45, 0.8, 1.0];
    for (final progress in downloadProgressStops) {
      await Future<void>.delayed(const Duration(seconds: 1));
      if (!_isDownloading) {
        return;
      }
      //更新progress
      _progress = progress;
      notifyListeners();
    }

    await Future<void>.delayed(const Duration(seconds: 1));
    if (!_isDownloading) {
      return;
    }
    //切换到下载完毕状态
    _downloadStatus = DownloadStatus.downloaded;
    _isDownloading = false;
    notifyListeners();
  }
}

因为下载是一个比较长的过程,所以这里用的是异步方法,在异步方法中进行通知。

定义DownloadButton的细节

有了可以动态变化的状态和进度之后,我们就可以在DownloadButton中构建具体的页面展示了。

在未开始下载之前,我们希望downloadButton是一个长条形的按钮,按钮上的文字显示GET,下载过程中希望是一个类似CircularProgressIndicator的动画,可以根据下载进度来动态变化。

同时,在下载过程中,我们希望能够隐藏之前的长条形按钮。 下载完毕之后,再次展示长条形按钮,这时候按钮上的文字显示为OPEN。

因为动画比较复杂,所以我们将动画组件分成两部分,第一部分就是展示和隐藏长条形的按钮,这里我们使用AnimatedOpacity来实现文字的淡入淡出的效果,并将AnimatedOpacity封装在AnimatedContainer中,实现decoration的动画效果:

  return AnimatedContainer(
      duration: transitionDuration,
      curve: Curves.ease,
      width: double.infinity,
      decoration: shape,
      child: Padding(
        padding: const EdgeInsets.symmetric(vertical: 6),
        child: AnimatedOpacity(
          duration: transitionDuration,
          opacity: isDownloading || isFetching ? 0.0 : 1.0,
          curve: Curves.ease,
          child: Text(
            isDownloaded ? 'OPEN' : 'GET',
            textAlign: TextAlign.center,
            style: Theme.of(context).textTheme.button?.copyWith(
              fontWeight: FontWeight.bold,
              color: CupertinoColors.activeBlue,
            ),
          ),
        ),
      ),
    );

实现效果如下所示:

接下来再处理CircularProgressIndicator的部分:

 Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 1,
      child: TweenAnimationBuilder<double>(
        tween: Tween(begin: 0, end: downloadProgress),
        duration: const Duration(milliseconds: 200),
        builder: (context, progress, child) {
          return CircularProgressIndicator(
            backgroundColor: isDownloading
                ? CupertinoColors.lightBackgroundGray
                : Colors.white.withOpacity(0),
            valueColor: AlwaysStoppedAnimation(isFetching
                ? CupertinoColors.lightBackgroundGray
                : CupertinoColors.activeBlue),
            strokeWidth: 2,
            value: isFetching ? null : progress,
          );
        },
      ),
    );
  }

这里使用的是TweenAnimationBuilder来实现CircularProgressIndicator根据不同progress的动画效果。

因为在下载过程中,还有停止的功能,所以我们在CircularProgressIndicator上再放一个stop icon,最后将这个stack封装在AnimatedOpacity中,实现整体的一个淡入淡出功能:

         Positioned.fill(
            child: AnimatedOpacity(
              duration: transitionDuration,
              opacity: _isDownloading || _isFetching ? 1.0 : 0.0,
              curve: Curves.ease,
              child: Stack(
                alignment: Alignment.center,
                children: [
                  ProgressIndicatorWidget(
                    downloadProgress: downloadProgress,
                    isDownloading: _isDownloading,
                    isFetching: _isFetching,
                  ),
                  if (_isDownloading)
                    const Icon(
                      Icons.stop,
                      size: 14,
                      color: CupertinoColors.activeBlue,
                    ),
                ],
              ),
            ),

总结

这样,我们一个动画的下载按钮就制作完成了,效果如下:

本文的例子:http://github.com/ddean2009/learn-flutter.git

本文转载于网络 如有侵权请联系删除

相关文章

  • mysql统计账单信息(下):数据导入及查询

    上一篇mysql统计账单信息(上):mysql安装及客户端DBeaver连接使用介绍了mysql5.7的安装及客户端DBeaver的连接配置,本文接上一篇内容,介绍数据导入和查询导出。一、excel导入数据的导入可以是excel也可以是导库,这里先介绍excel导入方式1.转csv将xlsx格式转换为csv模式2.转码使用notepad打开并转码为UTF-83.导表将excel导入数据库下一步选择移动对账单下一步报错:该报错原因为无权限,授权即可GRANTSELECT,INSERT,UPDATE,DELETE,CREATE,DROPONzd.*TOloong576@’%’identifiedby‘root’;复制4.表查看表数据查看二、恢复数据库本节演示restore数据库方式导入数据选择要导入的sql文件,执行导入,导入前需要授权grantallprivilegeson`liuliangkafukuan`.*to'loong576'@'%'identifiedby'Loong576!';复制执行导入导入过程可能会涉及到max

  • 一文详解 32 位保护模式与内存分段机制

    1.引言此前我们对操作系统中的分段、分页机制以及虚拟地址、逻辑地址、线性地址、物理地址进行了较为详细的介绍。 操作系统的内存管理—分段与分页、虚拟地址、逻辑地址、线性地址、物理地址那么操作系统为什么要实现这一系列复杂的机制呢?上文提到的GDT、LDT、IDT又是什么呢?他们的结构是什么样的呢?保护模式中的“保护”体现在哪里呢? 本文就让我们来一探究竟。2.实地址模式此前的文章中,我们在系统启动时,通过触发BIOS中断,实现了在屏幕上显示出“HelloWorldmyOS!”。 计算机是如何启动的?如何制作自己的操作系统这段代码始终是运行在实地址模式中的,在实地址模式中,内存地址是通过cs、ds等16位段寄存器存储的段基址与16位段偏移共同计算出20位的物理地址的:物理地址=段基址*16+段偏移这样计算的原因是为了兼容Intel8086CPU,8086CPU由若干个16位寄存器、16位的数据总线以及20位的地址总线组成,通过段地址与段偏移组合成的20位地址提供了1MB内存空间的寻址能力。 但我们已经看到,在实地址模式下,应用程序可以读取、修改整个内存空间,这让CPU必须在一个进程完全运行结

  • Python 3.11 ,即将变得更快!

    这是「进击的Coder」的第632 篇技术分享来源:CSDN“阅读本文大概需要5分钟。”作为一门异常受欢迎的编程语言,Python的优点有很多,比如:易于学习、用途广泛、有成千上万个用于数据科学的有用的库。但同时,Python一直被诟病的就是它运行速度太慢。 在去年的PyConUS2021大会上,Python之父GuidovanRossum曾表示:要在2022年的Python3.11中,将Python速度提高2倍,4年内,速度提升5倍,以解决Python与C++等其他编程语言相比在速度上的关键缺点。如今,速度太慢的情况在Python3.11中即将改变。在今年晚些时候发布稳定版之前,目前正处于其预览版(版本3.11.0b1)的第一个测试阶段。CPython3.11已比3.10提速1.25倍在近期的PyConUS2022会议上,CorePython(CPython)开发者MarkShannon分享了关于加速Python项目的细节,此外,开发者还展示了在浏览器中运行Python代码这一目标的进展。去年,微软资助了Python软件基金会(PSF)的一个项目——“ShannonPlan”,该项目

  • Python os.path模块的使用

    Python的os模块是一个对接操作系统的模块,当我们需要对路径进行操作时,可以使用os.path。os.path模块实现了很多处理长文件名,长路径名的函数,可以用来对路径切分,拼接,转换等。先导入os模块,然后就可以使用os.path模块了。一、os.path获取路径#coding=utf-8 importos #返回当前位置的绝对路径 print(os.getcwd()) print(os.path.abspath('.')) #返回path的真实路径 print(os.path.realpath('..')) #返回从start开始计算的相对路径 print(os.path.relpath('.','/home/python/Desktop'))复制运行结果:/home/python/Desktop/python_demo/os_test /home/python/Desktop/python_demo/os_test /home/python/Desktop/python_demo python

  • android仿直播圆点加载效果

    今天实现一个很多app中使用到的加载进度条的效果,可能我们平时数据加载都使用到的是系统自带的,但是也有很多app加载进度条的效果实现挺好看,就是三个点不停的水平跑而且是变换颜色的,其实这个效果很简单,分析:第一步:第二步:为了圆的颜色大小,以及移动的距离都对外开放,采用了自定义属性的方式,当然也可以进行设置,分析了后代码就直接上了,<?xmlversion="1.0"encoding="utf-8"? <resources <declare-styleablename="CirclePointLoadView" <attrname="leftPointColor"format="color|reference"</attr <attrname="middlePointColor"format="color|reference"</attr <attrname="rightPointColor

  • 如何在Excel中设置单元格只能输入正值?

    Excel技巧:如何在Excel中设置单元格只能输入正值?今天培训的客户咨询,如果能让输入的单元格只能输入正值?正值就是大于0的数据吗?是只能输入数值?经过确认后,希望能限制单元格只能输入数值,而且是正数。Excel果然是强大的,这种问题分分钟搞定。与大家分享一下。场景:适合公司人事、行政、财务、销售等进行专业统计的办公人士。问题:如何设置单元格只能输入正值?解答:利用Excel的数据验证(数据有效性)功能搞定。具体操作如下:首先选中下图中“数量”字段下面的区域,点击“数据-数据验证”按钮。(下图3处)在新弹的“数据验证”窗口中,设置验证条件,允许“小数”,数据“大于”,最小值为“0”(下图4处) 确定后,赶紧来测试一下效果。1.输入汉字2.不允许录入,很好。 2.输入负数试试,不允许输入,很好。 总结:“Excel2013的数据验证”在Excel2010中叫做“数据有效性”,数据有效性是Excel定制工作模板中非常重要一种技巧。大家有兴趣可以深入研究,也会后续技巧中发布。该技巧Excel007版本及以上有效。

  • 【CSS】464- 5种 CSS 浮动和清除浮动的方法

    浮动是布局的时用到的一种技术,能够方便我们进行布局。 1、浮动的设置:css属性float:left/right/none左浮动/右浮动/不浮动(默认)2、浮动的原理:使当前元素脱离普通流,相当于浮动起来一样,浮动的框可以左右移动,直至它的外边缘遇到包含框或者另一个浮动框的边缘 3、浮动的影响:对附近的元素布局造成改变,使得布局混乱因为浮动元素脱离了普通流,会出现一种高度坍塌的现象:原来的父容器高度是内部元素撑开的,但是当内部元素浮动后,脱离普通流浮动起来,那父容器的高度就坍塌,变为高度0px。如下图:清除浮动的5种方法1、父级div定义overflow:hidden原理:使用overflow:hidden时,浏览器会自动检查浮动区域的高度。 优点:简单,代码少,浏览器支持好。 缺点:必须定义width或zoom:1,不能和position配合使用,因为超出的尺寸的会被隐藏。 建议:只推荐没有使用position或对overflow:hidden理解的朋友使用。2、结尾处加空div标签clear:both原理:添加一个空div,利用css提高的clear:both清除浮动,让父级div

  • LeetCode之Add Two Numbers

    AddTwoNumbers方法一:  考虑到有进位的问题,首先想到的思路是:  先分位求总和得到totalsum,然后再将totalsum按位拆分转成链表;1ListNode*addTwoNumbers(ListNode*l1,ListNode*l2){ 2intsum=0; 3inti=1; 4while(l1!=NULL&&l2!=NULL) 5{ 6sum+=i*(l1->val+l2->val); 7i*=10; 8l1=l1->next; 9l2=l2->next; 10} 11while(l1!=NULL) 12{ 13sum+=i*(l1->val); 14i*=10; 15l1=l1->next; 16} 17while(l2!=NULL) 18{ 19sum+=i*(l2->val); 20i*=10; 21l2=l2->next; 22} 23//fen 24ListNode*head=newListNode(0); 25ListNode*p=head; 26if(sum==0)returnhead;

  • 图片语义分割-FCN

    首先说下什么是语义分割,语义分割是从像素的水平上来理解识别图像,相当于知道每一个像素是什么东西。可用于自动驾驶和医学上的。早先是利用手工特征加图模型。随着深度网络的发展,也引入的CNN,传统的CNN是有问题的:a.网络的后半段空间信息的缺失;b.输入的图片的尺寸固定。为了改进这个FCN到来了,FCN(FullyConvolutionalNetworks)又全卷积网络,如它的名字一样,它的所有层都是卷积层,很好的解决了降采样后的低分辨率问题。对每一个像素进行预测FCN有三个重要的东西:卷积化;反卷积;跳层结构。卷积化:全连接层(6,7,8)都变成卷积层,适应任意尺寸输入,输出低分辨率的分割图片。开始的5个卷积层,使图像的分辨率下降了32倍,每层降低2倍。降主要是因为Pooling池化层,相当于扫描四个像素选一个,扫描的步长是2。后面的三层是没有降采样的。我自己有画一个卷积的降纬的图解。如下第二个图:反卷积:低分辨率的图像进行上采样,输出同分辨率的分割图片。有两点注意的反卷积的卷积核是不变的。对于偶输出,有外围全部补0的反卷积,对于奇输出,有插空补0的反卷积。如下图:输入是2X2卷积的偶的

  • 为什么很多外国工程师不愿当领导?当领导好还是当工程师好?

    为什么国外工程师能够专心做技术?当领导好还是当工程师好?最近,在想一个问题,为什么国外的工程师很多不想升职,而是专心做技术。我曾经就职一家外企,而这家公司的很多外国同事,其实是相当于外包性质的。他们的技术水平非常高。感觉他们和公司的正式员工都非常熟悉,于是就了解了一下。原来他们原本是这家公司的正式员工,后来因为公司业务原因,被裁员了,然后,他们又再次以外包人员的身份,继续给公司工作。由于他们本来就是这里的老员工,所以业务水平非常好。这让我想到了我经历的另外一家,同样是外企,也是由于公司想降低成本。于是公司想到了裁员。思来想去,干活的工程师,总还是需要的,这时候看到了我们部门的总监。美国人觉得他工资很高,似乎又没干啥实事,于是把他裁掉了。他下面的人一个没裁。然后,我们整组人都归给了另外一个领导。后来,我们这位领导很快找到了新的公司,新的职位,还带走了好几个技术骨干。毕竟人家能力还是有的。不过后来听说,新公司又裁员了。他有没有找下家,我就不知道了。从这两件事,你有没有感到一丝寒意。难道我们追求的当领导作为目标,错了?搞技术,公司不愿意裁,甚至即使裁,最后也还是请了回来。领导被裁,反而对公司

  • 工作常用之Hive 调优【三】 Explain 查看执行计划及建表优化

    第1章Explain查看执行计划(重点)1.1创建测试用表1)建大表、小表和JOIN后表的语句//创建大表createtablebigtable(idbigint,tbigint,uidstring,keywordstring,url_rankint,click_numint,click_urlstring)rowformatdelimitedfieldsterminatedby'\t';//创建小表createtablesmalltable(idbigint,tbigint,uidstring,keywordstring,url_rankint,click_numint,click_urlstring)rowformatdelimitedfieldsterminatedby'\t';//创建JOIN后表createtablejointable(idbigint,tbigint,uidstring,keywordstring,url_rankint,click_numint,click_urlstring)rowformatdelimitedfi

  • 腾讯云政策与规范云托管服务等级协议(SLA)

    为使用腾讯云云托管服务(以下简称“本服务”),您应当阅读并遵守《云托管服务等级协议》(以下简称“本协议”或“SLA”),以及《腾讯云服务协议》。本协议包含本服务的术语和定义、服务可用性/服务成功率等级指标、赔偿方案、免责条款等相关内容。请您务必审慎阅读、充分理解各条款内容,限制、免责条款或者其他涉及您重大权益的条款可能会以加粗、加下划线等形式提示您重点注意。 除非您已充分阅读、完全理解并接受本协议所有条款,否则,请您不要购买本服务。您单击“同意”、“下一步”或您的购买、使用等行为或者您以其他任何明示或者默示方式表示接受本协议的,即视为您已阅读并同意本协议的约束。本协议即在您与腾讯云之间产生法律效力,成为对双方均具有约束力的法律文件。 1.术语和定义1.1腾讯云云托管服务云托管(TencentCloudBaseRun)是云开发(TencentCloudBase,TCB)提供的新一代云原生应用引擎(AppEngine2.0),支持托管用任意语言和框架编写的容器化应用。和云开发其他产品(云函数、云数据库、云存储、扩展应用、HTTP访问服务、静态网站托管等)一起为用户提供云原生一体化开发环境和

  • c++ operator操作符的两种用法:重载和隐式类型转换,string转其他基本数据类型的简洁实现string_cast

    转载自:https://www.cnblogs.com/yangxudong/p/3872053.html C++中的operator主要有两个作用,一是操作符的重载,一是自定义对象类型的隐式转换。对于操作符的重载,许多人都不陌生,但是估计不少人都不太熟悉operator的第二种用法,即自定义对象类型的隐式转换,我们下面就用以下这个小例子温故一下这两种用法: 1#include<iostream> 2#include<sstream> 3usingnamespacestd; 4 5classFuncObj 6{ 7public: 8FuncObj(intn):_n(n){ 9cout<<"constructor"<<endl; 10} 11 12booloperator()(intv){ 13cout<<"operatoroverload"<<endl; 14returnv>_n; 15} 16 17operatorstring(){ 18cout<<"typeconvert"<<

  • sh脚本异常:/bin/sh^M:bad interpreter: No such file or directory

    在Linux中执行.sh脚本,异常/bin/sh^M:badinterpreter:Nosuchfileordirectory。 分析:这是不同系统编码格式引起的:在windows系统中编辑的.sh文件可能有不可见字符,所以在Linux系统下执行会报以上异常信息。 解决:1)在windows下转换: 利用一些编辑器如UltraEdit或EditPlus等工具先将脚本编码转换,再放到Linux中执行。转换方式如下(UltraEdit):File-->Conversions-->DOS->UNIX即可。 2)也可在Linux中转换: 首先要确保文件有可执行权限 #sh>chmoda+xfilename 然后修改文件格式 #sh>vifilename 利用如下命令查看文件格式 :setff或:setfileformat 可以看到如下信息 fileformat=dos或fileformat=unix 利用如下命令修改文件格式 :setff=unix或:setfileformat=unix 最后再执行文件 #sh>./filename

  • CodeForces1328F 贪心

    题意 给你一个由n个元素和k≤n的整数组成的数组a。您要在数组a中获得至少k个相等的元素。一次移动,可以执行以下两个操作之一:取数组的最小元素之一,并将其值增加1取数组的最大元素之一,并将其值减少1您的任务是计算在数组中至少获得k个相等元素所需的最小移动次数。 Input 输入的第一行包含两个整数n和k(1≤k≤n≤2⋅105),即a中的元素数和所需的相等元素数。输入的第二行包含n个整数a1,a2,…,an(1≤ai≤109),其中ai是a的第i个元素。 Output 打印一个整数-在数组中获得至少k个相等元素所需的最小移动次数。 题解 针对其中的某一个元素(大小i,出现次数为j),如果我们想要将他的数量达到到K,共有四种情况 他本身的出现次数超过K次 将比它小的所有数字补充到i-1,然后选取K-j个数字增大到i 将比它大的所有数字补充到i+1,然后选取K-j个数字减小到i 将比它小的所有数字补充到i+1,比它小的所有数字补充到i-1,然后选取K-j个数字到i 除开情况1之外,其他情况的第一步操作(将其余数字补充到i±1)都是一个常数,可以直接用前缀和求出,求出之后O(n)的时间遍

  • 在eclipse中使用mybatis-generator自动创建代码

    1.eclipse中安装插件,地址:http://mybatis.googlecode.com/svn/sub-projects/generator/trunk/eclipse/UpdateSite/ ps:这个插件不知道是不是要FQ,我是用了VPN 2.写xml配置文件:generatorConfig.xml 1<?xmlversion="1.0"encoding="UTF-8"?> 2<!DOCTYPEgeneratorConfiguration 3PUBLIC"-//mybatis.org//DTDMyBatisGeneratorConfiguration1.0//EN" 4"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> 5<generatorConfiguration> 6<!--数据库驱动--> 7<classPathEntrylocation="C:\Users\admin\workspace\prac\mysql-connector-java-

  • JSP学习-sessionDemo

    一个简单的Demo: 一个登陆页面login.jsp,跳转到check.jsp,登陆成功就跳转到welcome.jsp,失败就跳转回login.jsp 并且非活动时间大于10秒也自动跳转回login.jsp login.jsp 1<%@pagelanguage="java"contentType="text/html;charset=UTF-8" 2pageEncoding="UTF-8"%> 3<!DOCTYPEhtml> 4<html> 5<head> 6<metacharset="UTF-8"> 7<title>Inserttitlehere</title> 8</head> 9<body> 10<formaction="check.jsp"method="post"> 11<!--登录后去哪里校验--> 12用户名:<inputtype="text"name="uname"><br>密码:<input 13type=

  • mysql.connector-创建数据库表test(id, sname, age)其中id为主键自增,sname不能为空

    importmysql.connector conn=mysql.connector.Connect( host='localhost', user='root', passwd='admin', database='testcode' ) print('1.',conn) cmd=conn.cursor()#光标行 cmd.execute('''createtabletest( idintprimarykeyauto_increment, snamechar(10)notnull, ageint);''')复制  

  • ORA-28040: 没有匹配的验证协议

    ORA-28040:没有匹配的验证协议 虽然在sqlnet.ora加SQLNET.ALLOWED_LOGON_VERSION=8可以解决, 但由于这个参数在12c已经废弃了,如果继续使用,会在alert/log.xml无穷无尽的报“UsingdeprecatedSQLNET.ALLOWED_LOGON_VERSIONparameter.” 因此,正确的做法是在$ORACLE_HOME/network/admin/sqlnet.ora加 SQLNET.ALLOWED_LOGON_VERSION_SERVER=8SQLNET.ALLOWED_LOGON_VERSION_CLIENT=8 区别如下:SQLNET.ALLOWED_LOGON_VERSION_SERVER:控制可以连接到12c数据库的客户端版本(client—>orace12cdb)SQLNET.ALLOWED_LOGON_VERSION_CLIENT:控制12c数据库可以连到哪些版本的数据库(orace12cdb—>其它版本的oracledb),例如:控制通过DBLINK可连接到哪些版本的oracle库。 特别需要

  • C语言:二级指针函数传值

     

  • Spring中Quartz的配置

    Quartz是一个强大的企业级任务调度框架,Spring中继承并简化了Quartz,下面就看看在Spring中怎样配置Quartz: 首先我们来写一个被调度的类: package com.kay.quartz; public class QuartzJob {     public void work()     {     System.out.println("Quartz的任务调度!!!");     } } Spring的配置文件: xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring

相关推荐

推荐阅读