中间件

中间件

容器服务 #

tomcat #

## 介绍
    tomcat从7开始默认就是nio的
## 配置
    bin/startup.bat
            set JAVA_HOME=
                            # 设置tomcat运行jdk
    context.xml
        <Loader delegate="true"/>
                # true表示使用java加载器的代理模式
                ## false代表永远先在Web应用程序中寻找
    web.xml
        Content-Type: text/x-zim-wiki
        Wiki-Format: zim 0.4
        Creation-Date: 2013-08-04T19:40:08+08:00

        ====== web.xml文件 ======
        Created Sunday 04 August 2013

        <servlet>
                <servlet-name>
                <servlet-class>
                <load-on-startup>1
                <init-param>
                        <param-name>
                        <param-value>
        <servlet-mapping>
                <servlet-name>
                <url-pattern>

        <welcome-file-list>
                <welcome-file>

        <filter>
                <filter-name>
                <filter-class>
                <init-param>
        <filter-mapping>
                <filter-name>
                <url-pattern>

        <mime-mapping>
                <extension>bmp
                <mime-type>image/bmp

        <error-page>
                <exception-type>异常类的完全限定名 /<error-code>错误码
                <location>以“/”开头的错误处理页面路径

## 启动顺序
    web.xml中配置的启动顺序
            监听器
            过滤器
            servlet
                    load-on-startup属性值越小越先启动

    tomcat的加载过程:        # 分析启动日志得到
            启动http协议
            启动catalina
            启动servlet引擎
            加载xml配置文件
            初始化日志配置
            初始化ContextListener
            初始化SessionListener
            部署web项目
                    spring监听器,加载xml配置(开始spring自己的日志记录)
                            实例化bean
                                    初始化c3p0连接池的记录显示
                                    初始化LocalSessionFactoryBean的记录显示
                    application监听器(监听器按配置顺序启动)
                    struts过滤器,加载xml配置(开始struts自己的日志记录)
                            struts-default.xml
                                    根据其中配置的bean属性加载类,并记录了日志
                            struts-plugin.xml                # 里面有加载spring-struts-plugin包
                                    初始化struts-spring 集成
                            struts.xml
## 目录
    LICENSE
    NOTICE
    RELEASE-NOTES
    RUNNING.txt
    bin
            bootstrap.jar
            commons-daemon.jar
            tomcat-juli.jar
            tomcat-native.tar.gz
            commons-daemon-native.tar.gz
            catalina.bat
            shutdown.bat
            startup.bat
            cpappend.bat
            digest.bat
            setclasspath.bat
            tool-wrapper.bat
            version.bat
            catalina.sh
            shutdown.sh
            startup.sh
            digest.sh
            setclasspath.sh
            tool-wrapper.sh
            version.sh
            catalina-tasks.xml
    conf
            catalina.policy
            catalina.properties
            logging.properties
            context.xml
            server.xml
            tomcat-users.xml
            web.xml
            Catalina
                    localhost
                            host-manager.xml
                            manager.xml
    lib
            annotations-api.jar
            catalina.jar
            catalina-ant.jar
            catalina-ha.jar
            catalina-tribes.jar
            el-api.jar
            jasper.jar
            jasper-el.jar
            jasper-jdt.jar
            jsp-api.jar
            servlet-api.jar
            tomcat-coyote.jar
            tomcat-dbcp.jar
            tomcat-i18n-es.jar
            tomcat-i18n-fr.jar
            tomcat-i18n-ja.jar
    log
            catalina.2013-07-28.log等等
    webapps
            ROOT
                    WEB-INF
                            web.xml
            docs
            examples
            manager
            host-manager
    tmp
    work

    发布
            conf/server.xml 中8080端口 位置
            <Context path="/bbs" reloadable="true" docBase="E:\workspace\bbs" workDir="E:\workspace\bbs\work" />

    发布war文件:
            localhost:8080 -> tomcat manager -> WAR file to deploy

netty #

介绍
    JBOSS提供,由Trustin Lee开发,比mina晚
    java开源框架
对比java nio
    java原生nio有bug(epoll bug)且编写困难, 网络可靠性自己处理
    netty设计优雅,使用方便,高性能、稳定
原理
    基于socket的数据流处理
        # socket数据流不是a queue of packets , 而是a queue of bytes, 所以分次传输的数据会成为a bunch of bytes
例子
    Handler
        ChannelHandler
            ChannelOutboundHandler
                    ChannelOutboundHandlerAdapter                        # 可作Encoder
                    MessageToByteEncoder
            ChannelInboundHandler                # 提供可重写的事件
                    ChannelInboundHandlerAdapter
                    ByteToMessageDecoder        # easy to deal with fragmentation issue
                            事件
                                    decode(ctx, in, out)                        # 内部处理过数据,堆积到了buffer(in)
                                                                            ## out中add了数据, 表示decode成功,则执行后抛弃in中数据
                                                                            # decode会被循环调用直到有一次out中没有add东西
                    ReplayingDecoder
                    事件
                            channelRead()                # 从client接收到数据时调用,数据的类型是ByteBuf
                                                    ## ByteBuf是 reference-counted object
                                                    ## 必须用ReferenceCountUtil.release(msg)或((ByteBuf) msg).release()来明确释放
                            exceptionCaught()        # 当抛出Throwable对象时调用
                            channelActive()                # as soon as a connection is established
            方法
                    handlerAdded()
                    handlerRemoved()
        ByteBuf
            方法
                    buf.writeBytes(m)                # 将m[ByteBuf]中的数据 cumulate into buf[ 定长的ByteBuf, 如ctx.alloc().buffer(4) ]
                    isReadable()                        # 返回ByteBuf中data的长度
        ChannelHandlerContext                # 用于触发一些i/o事件
            方法
                    write(msg)                # msg在flush后自动realease
                            write(msg, promise)                                # promise是ChannelPromise的对象,用来标记msg是否确切地写入到管道中
                    flush()
                    writeAndFlush(msg)                                        # 返回ChannelFuture
                    alloc()                                                        # 分配缓冲区来包含数据
        ByteBufAllocator
            buffer(4)                        # 返回存放32-bit Integer的ByteBuf
    Server
        EventLoopGroup
            NioEventLoopGroup                # 多线程 i/o eventloop
            方法
                    shutdownGracefully()                                                # 返回Funture类来通知group是否完全关闭并且所有group的channels都关闭
        ServerBootstrap                        # 建server的帮助类,链式编程
                                            ## 可以直接用Channel来建server
            方法
                group(bossGroup, workerGroup)                                # boss接收连接,worker处理boss中的连接
                        group(workerGroup)                                        # 只有一个参数时,该group即作boss也作worker
                channel(NioServerSocketChannel.class)                        # 用来接收连接的channel的类型
                        channel(NioSocketChannel.class)                        # create client-side channel
                childHandler(channelInitializer)                                # 新接收的channel总执行本handler
                                                                                ## 只有workerGroup时不用
                option(ChannelOption.SO_BACKLOG, 128)                        # channel实现的参数
                childOption(channelOption.SO_KEEPALIVE, true)                # option设置boss, childOption设置worker
                                                                                ## 在只有workerGroup时不用childOption,因为它没有parent
                bind(port)                                                        # 开始接收连接,返回的是ChannelFuture
                                                                                    ## 绑定网卡上的所有port端口,可以bind多次到不同的端口
        ChannelInitializer                        # 帮助设置channel, 如设置channel的pipeline中的handler
            实例
                new ChannelInitializer<SocketChannel>(){
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception{
                                ch.pipeline().addLast(new DiyHandler());
                        }
                }
        ChannelFuture
            方法
                sync()
                channel()                                                        # 返回Channel
                addListener(channelFutureListener)
        Channel
                closeFuture()                                                        # 返回ChannelFuture
        ChannelFutureListener
            实例
                new ChannelFutureListener(){
                    // 当请求结束时通知
                    @Override
                    public void operationComplete(ChannelFuture future){
                        assert f == future;
                        ctx.close();
                    }
                }
    client
        Bootstrap                        # for non-server channels such as a client-side or connectionless channel
            connect(host, port)

netty-tcnative #

介绍
        tomcat native 的分支
特点
        简化本地库的分配和连接
        可以maven配置dependency
        提供openssl的支持

jetty #

# 是开源的servlet容器,基于java, 可以给jsp和servlet提供运行环境
# jetty容器可以实例化成一个对象,迅速为一些独立运行(stand-alone)的java应用提供网络和web连接

apache #

# http容器,可容纳php, python。一请求一线程
安装
    pacman -S apache
    mkdir /srv/http
    chown http:http /srv/http
编译安装
    ./configure
        --prefix=/全路径/install_path
        --with-apxs2=/全路径/apxs            # 模块
    make
    make install
命令
    httpd
        -f                                  # 指定配置
        -t                                  # 配置检查
        -k
            start
            restart
            graceful
            stop
            graceful-stop
    apachectl
        graceful                            # 重载配置
        -f /全路径/httpd.conf                # 指定配置
        -t                                  # 配置检查
配置
    /etc/httpd/conf/httpd.conf
        DocumentRoot "/srv/http"            # 项目路径
        Listen                              # 端口
案例
    php
        docker解决

lighttpd #

meteor #

# 包装node

ringojs #

# jvm上commonJs规范的服务器

mina #

apache提供, 由Trustin Lee开发,比netty更早

tomcat native #

# 基于apr(apache portable runtime)技术,让tomcat在操作系统级别的交互上做的更好

tinyHttpd #

resin #

# 收费, 类似tomcat的java容器,性能提升

uwsgi #

# 一个web服务器,实现了wsgi, uwsgi, http等协议

weblogic #

# oracle

was #

# ibm服务器

gunicon #

# python wsgi http server

node.js #

OpenResty #

# 基于Nginx扩展

Tengine #

# 基于Nginx扩展

数据库访问 #

Druid #

Sharding JDBC #

缓存 #

缓存失效策略
	FIFO(First Input First Output)
	LRU(Least Recently Used)
	LFU(Least Frequently Used)

客户端缓存 #

Header
	Cache-Control: no-cache, no-store, max-age=0, must-revalidate
	Vary: Accept-Encoding
	Vary: Origin
	Vary: Access-Control-Request-Method
	Vary: Access-Control-Request-Headers
	Vary: Origin
	Vary: Access-Control-Request-Method
	Vary: Access-Control-Request-Headers

本地缓存 #

Ehcache
	堆内、堆外、磁盘三级缓存,可按容量制定缓存策略
	可按时间、次数制定过期策略
Guava Cache
	堆内缓存
Nginx本地缓存
Nginx PageSpeed插件

缓存服务 #

HTTP
	Nuster
		基于HAProxy的HTTP缓存服务器
	Varnish
		3台Varnish代替12台Squid
	Squid
Memcached
Redis
Tair

配置、服务发现 #

Apollo #

# 支持推、拉模式更新

Eureka #

Nacos #

RPC #

Dubbo #

Thrift #

gRPC #

消息队列 #

消息重发
    状态表记录消息状态

pulsar #

# 雅虎开源, 存储和服务分离,高可用存储, 支持流

rabbitMQ #

介绍
    erlang开发, 重量级
    支持协议多,AMQP、XMPP、SMTP、STOMP
    Broker构架        # 消息在中心队列排队
install
        yum install rabbitmq-server
命令
        添加用户:
                rabbitmqctl add_user rainbird password
        添加权限:
                rabbitmqctl set_permissions -p "/" rainbird ".*" ".*" ".*"
        删除测试用户:
                rabbitmqctl delete_user guest
原理
    虚拟主机 virtual host: 用户通过虚拟主机进行权限控制(如禁止A组访问B组的交换机)
            # 默认虚拟主机为"/"
            队列 queue: 由生产者(producers)通过程序建立,再通过消费者(consuming)连接取走
                    消息:
                            路由键 routing key
            交换机 exchange: 负责把消息放入队列
                    绑定 binding(路由规则): 如指明交换机中具有路由键"X"的消息要到名为"Y"的队列中去
                            # 如果同一个键对应多个队列,则复制后分别发送

    功能
            持久化
                    队列和交换机创建时指定标志durable,指定队列和交换机重启生重建
                            # 如果绑定了durable的队列和durable的交换机,该绑定自动保留
                            # non-durable的交换机与durable的队列不能绑定
                            # 一但创建durable标志,不能修改
                    消息发布到交换机时,指定标志Delivery Mode=2,这样消息会持久化
使用(原文http://adamlu.net/rabbitmq/tutorial-one-python)
        安装python 与插件支持
                pip
                python-pip git
                python-pika
        rabbitmq-server start
        send.py
            #!/usr/bin/env python
            import pika

            connection = pika.BlockingConnection(pika.ConnectionParameters(
                    host='localhost'))
            channel = connection.channel()

            channel.queue_declare(queue='hello')

            channel.basic_publish(exchange='',
                                routing_key='hello',
                                body='Hello World!')
            print " [x] Sent 'Hello World!'"
            connection.close()
                    receive.py
                            #!/usr/bin/env python
            import pika

            connection = pika.BlockingConnection(pika.ConnectionParameters(
                    host='localhost'))
            channel = connection.channel()

            channel.queue_declare(queue='hello')

            print ' [*] Waiting for messages. To exit press CTRL+C'

            def callback(ch, method, properties, body):
                print " [x] Received %r" % (body,)

            channel.basic_consume(callback,
                                queue='hello',
                                no_ack=True)

            channel.start_consuming()

jafka #

介绍
    基于kafka, 快速持久化(O(1)时间开销)
    高吞吐,一台普通服务器 100k/s
    完全分布式,Broker, Producer, Consumer原生支持分布式,自动负载均衡
    支持hadoop并行加载

kafka #

介绍
    apache子项目,scala语言编写, 发布订阅队列
    相对activeMQ轻量
特点
    push/pull队列架构,适合异构集群
    分布式, 高吞吐率, 易扩展
    支持数据并行到hadoop
    分区有序
    批量压缩, 零拷贝, 内存缓冲, 磁盘顺序写入
    可持久化
工具
    manager # 监控

nsq #

介绍
    go
工具
    admin   # 监控

memcacheQ #

zeroMQ #

activeMQ #

介绍
    apache子项目, 类似zeroMQ
通信方式
    点到点
        不成功时保存在服务端
    发布订阅
        不成功消息丢失

beanstalkd #

mqtt #

# 最早由ibm提供的,二进制消息的mq

emqttd #

介绍
    mqtt broker

apollo #

介绍
    apache mqtt broker

metaq #

# 阿里mq

定时任务 #

Cron #

XXL Job #

quartz #

# java作业调度
配置applicationContext_job.xml
    job             # 任务内容
    jobDetail       # 调度方案
    trigger         # 时间
    scheduler       # jobDetail和trigger的容器
状态监控
    # 用日志表记录
    运行中
        JobListener监听器
    暂停中
        scheduler.pauseTrigger()
    等待中
        创建job时

celery #

# python

rundeck #

# java

存储服务 #

存储的概念和术语
    scsi: 小型计算机系统接口(Small Computer System Interface)
    fc: 光纤通道(Fibre channel)
    das: 直连式存储(Direct-Attached Storage)
    nas: 网络接入存储(Network-Attached Storage)
    san: 存储区域网络(Storage Area Network)
        连接设备: 路由,  光纤交换机, 集线器(hub)
        接口: scsi fc
        通信协议: ip scsi

iscsi #

# internet scsi
优点
    可以网络传输
    服务器数量无限
    在线扩容.动态部署
架构
    控制器架构: 专用数据传输芯片.专用RAID数据校验芯片.专用高性能cache缓存和专用嵌入式系统平台
    iscsi连接桥架构:
        前端协议转换设备(硬件)
        后端存储(scsi磁盘阵列.fc存储设备)
    pc架构
        存储设备搭建在pc服务器上,通过软件管理成iscsi, 通过网卡传输数据
        实现
            以太网卡 + initiator软件
            toe网卡 + initiator软件
            iscsi HBA卡
iscsi系统组成
    iscsi initiator 或 iscsi hba
    iscsi target
    以太网交换机
    一台或多台服务器

fastdfs #

# 开源分布式文件系统

cdn #

介绍
    流量不大时带宽比cdn便宜, 流量大时cdn便宜。
    界限为250Mbps左右,价格在9k/month
价格     50TB/月        100TB/月
阿里云   3.8w/月        6.9w/月
盛大云   9k/月          1.7w/月
网宿
蓝汛

AWS S3 #

命令
    aws
        s3
            cp --recursive bin s3://meiqia/crm-module/search/bin
                # 级联复制
            sync s3://meiqia/crm-module/search/bin bin
                # 下载
            rm --recursive s3://meiqia/crm-module/search
                # 级联删除

网关 #

Zuul #

Spring Cloud Gateway #

Kong #

# 基于OpenResty

日志 #

ELK #

# elasticsearch, logstash, kibana
FileBeat
    命令
    filebeat --environment systemd -c /etc/filebeat/filebeat.yml --path.home /usr/share/filebeat --path.config /etc/filebeat --path.data /var/lib/filebeat --path.logs /var/log/filebeat

log.io #

DNS服务 #

Nscd #

DNS本地缓存

实时计算 #

阿里云Flink
	集群
		计算单元
		vertex拓扑
	名词
		DataHub源表
		RDS维表
		RDS结果表

支撑-分布式

名词 #

Alb        automaticLoopBack 自动回环,虚拟接口
sdn        software defined network 软件定义网络

Serverless #

knative
    # google开源,serverless标准化方案,基于kubernetes和istio
    模块
        build
        serving
        eventing

ServiceMesh #

Service Fabric #

# 微软

Istio #

#google IBM, lyft开源,基于envoy
组成
    数据面板
    控制面板

Knative #

介绍
    管理kubernetes, Istio
模块
    build
    serve
        config
        route
    event

Traefik #

# go实现,多后台如kubernetes, swarm, marathon, mesos

Linkerd #

# buoyant出品

Conduit #

# 面向kubernetes轻量化mesh

Fingle #

# twitter出品

Envoy #

# lyft出品

Nginmesh #

# nginx推出

PaaS #

# platform as a service

CloudStack #

# 托管在apache的开源、高可用、高扩展性的云计算平台
# 支持主流hypervisors
# 一个开源云计算解决方案,可以加速iaaS的部署、管理、配置

CloudFoundry #

# pivotal开源, 根据应用模板,动态生成很多tomcat, mysql, nosql, 动态控制这些实例的启停。

OpenStack #

# 云操作系统,管理虚拟资源

Container Orchestration #

特性 dubbo spring cloud kubernetes
配置管理 - config kubernetes configMap
服务发现 zookeeper eureka, consul, zookeeper kubernetes services
负载均衡 自带 ribbon kubernetes services
网关 - zuul kubernetes services
分布式追踪 - spring cloud sleuth open tracing
容错 不完善 hystrix kubernetes health check
通信方式 rpc http, message
安全模块 - spring cloud security -
分布式日志 ELK EFK
任务管理 spring batch kubernetes jobs

Kubernetes #

# google开源的,borg的发展,在docker技术上,管理容器化应用
特点
    不限语言
    无侵入, 服务只写业务
    适合微服务                       # 调整服务副本数, 横向扩容
    无缝迁移到公有云                  # cluster ip实现不改配置迁移
    自动化资源管理
        服务发现,用dns解析服务名
        内嵌负载均衡
        部署实施
        治理
        监控
        故障发现、自我修复
        透明服务注册、发现
        服务滚动升级、在线扩容, 根据负载自动扩容缩容
        可扩展资源自动调度、多粒度资源配额
    多层安全防护、准入
    多租户
    完善的工具

    pod运行容器
    etcd保存所有状态
架构
    cluster
        master
            api server              # 对外http rest接口, 管理资源对象(pod, RC, service)增删改查
            controller manager      # 管理控制器, node, pod, endpoint, namespace, serviceAccount, resourceQuota自动化管理
            scheduler               # 接收controller manager命令执行pod调度
            etcd                    # 配置
        node                        # 一master多node
            特点
                node宕机,pod调度到其它节点
            pod                     # 一node几百个pod, 基本操作单元,代表一个运行进程,内部封装一个(或多个紧密相关的)容器。
                特点
                    pod内通信高效,放密切相关服务进程
                    可以判断一组相关容器的状态(用pause)
                    pause解决共享ip、容器通信、共享文件的问题
                    pod间通信用虚拟二层协议(flannel, openvswitch)实现
                    普通pod在etcd存储,再调度到某node实例化,静态pod在node中存储,在node实例化
                    对pod可进行资源(cpu,内存)限额
                label               # 标签,用标签选择器选择。key和value由用户指定,可附加到node, pod, service, rc等
                pause容器            # 根容器,共享网络栈、挂载卷
            docker/rocket           # 容器
            kubelet                 # master监视pod, 创建、修改、监控、删除
            kube-proxy              # 代理pod接口
            fluentd                 # 日志收集、存储、查询
            kube-dns                # 服务dns解析
概念
    service                         # 服务网关
        特点
            唯一名字
            唯一虚拟ip(cluster ip, service ip, vip)                  # 可多端口,每端口有名字
            提供远程服务              # 目前socket
            应用到一组pod
    event                           # 探针检测失败记录,用于排查故障
    rc                              # replication controller
        副本数
        筛选标签
        pod模板
        改变pod镜像版本,滚动升级
    replica set                     # 1.2 rc升级, 支持基于集合的标签选择。被deployment使用
    deployment                      # pod编排, rc升级
        特点
            查看pod部署进度
    HPA                             # horizontal pod autoscaler, 自动扩容缩容
        指标
            cpu utilization percentage                              # 1分钟内利用率平均值
            应用自定义指标(tps, qps)
    volume
        emptyDir
        hostPath
        gcePersistentDisk
        awsElasticBlockStore
        NFS
        persistent volume
        namespace
        annotation
动作
    扩容
        创建rc自动创建pod, 调度到合适的node
            pod定义
            副本数
            监控label                # 筛选pod得到数量
命令
    kubectl
        --help                      # 帮助, 各命令之后都可加
        version
        cluster-info
        logs
            kubectl logs --tail=1000 appID1
                # 查看日志
        run
        exec
            kubectl exec -it appID1 /bin/sh
                # 交互命令进入app
        create
            -f mysql-rc.yaml        # 创建rc
            -f mysql-svc.yaml       # 创建service
        set 
            image
        get
            rc                      # 查看rc
            pods
            pod
                -o
                    wide            # 显示详情,有node name
                o->
                kubectl get pod -l app=app1 -o wide
                    # 查看pod app状态
            services
            svc                     # 查看service, 包含cluster ip
            nodes
            endpoints               # service pod的ip:端口
            deployments
        describe                    # 详情
            node
            pods
            deployments
        expose
        label
        delete
        scale                       # pod扩容或缩容
            --replicas=2
        autoscale                   # 创建hpa对象
            deployment
        rolling-update              # pod滚动升级
        rollout
            status
            undo
        apply                       # 应用配置
            -f
        proxy
    kubelet
    kube-apiserver
    kube-proxy
    kube-scheduler
    kubeadm
    kube-controller-manager
    hyperkube
    apiextensions-apiserver
    mounter
镜像
    kube-apiserver
    kube-controller-manager
    kube-scheduler
    kube-proxy
    pause
    etcd
    coredns
配置
    用yaml或json定义
    pod
        kind: Pod                   # 表明是Pod
        metadata:
            name: myweb             # pod名
            labels:
                name: myweb         # 标签

Spring Cloud #

Mesos #

# twitter, apache开源的分布式资源管理框架, 两级调度器

Dubbo #

介绍
    阿里开源,分布式服务框架,rpc方案,soa治理
功能
    远程通讯    # 多协议,多种长连接nio框架封装
    集群容错    # 负载均衡,容错,地址路由,动态配置
    自动发现    # 注册中心
节点
    容器(container)
    提供者(provider)
    消费者(consumer)
    注册中心(registry)
    监控中心(monitor)
    调用关系
        容器启动提供者
        提供者注册
        消费者订阅
        注册中心返回地址列表, 长连接更新
        消费者软负载均衡挑选列表中提供者
        提供者和消费者累计调用次数和时间,定时发送到监控中心
容错机制
    failover    # 默认,失败自动切换
    failfast    # 立即报错,用于幂等写操作
    failsafe    # 忽略
    failback    # 定时重发
    forking     # 并行多个取最快(any)
    broadcast   # 逐个多个,异常退出
连接方式
    广播      # 不需要中心节点,适用开发测试, 地址段224.0.0.0 - 239.255.255.255
        服务端配置 applicationContext-service.xml
            <dubbo:application name=”taotao-manager-service” />
            <dubbo:registry address=”multicast://224.5.6.7:1234” />
            <dubbo:protocol name=”dubbo” port=”20880” />
            <dubbo:service interface=”com.taotao.manager.service.TestService” ref=”testServiceImpl” />
        客户端配置 springMVC.xml
            <dubbp:application name=”taotao-manager-web” />
            <dubbo:registry address=”multicast://224.5.6.7:1234” />
            <dubbo:service interface=”com.taotao.manager.service.TestService” id=”testService”
            timeout=”10000000” />
    直连
        服务端配置
            <dubbo:application name=”taotao-manager-service” />
            <dubbo:registry address=”N/A” />
            <dubbo:protocol name=”dubbo” port=”20880” />
            <dubbo:service interface=”com.taotao.manager.service.TestService” ref=”testServiceImpl” /> applicationContext-service.xml
        客户端配置 springMVC.xml
            <dubbp:application name=”taotao-manager-web” />
            <dubbo:service interface=”com.taotao.manager.service.TestService” id=”testService”
            timeout=”10000000” />
注册中心
    zookeeper

Dubbox #

介绍
    当当网扩展Dubbo

Netflix OSS #

orleans #

# .NET

HSF #

# high-speed service framework, 阿里出品, socket直连
特点
    不增加中间点(稳定,高度可伸缩)
结构
    注册服务信息,推送服务地址
    基于osgi
组件
    服务提供者
    消费者
    地址服务器
    配置服务器               # 分布式配置
    规则服务(diamond)       # 设置(黑白名单,认证,权重,限流)与推送

NScale #

# 可扩展容器,用node.js和docker实现

Armada #

# python微服务

SOA #

# 面向服务架构 service oriented architecture

EAI #

# Enterprise Application Integration 建立底层结构将异构应用集成

ESB #

# Enterprise Service Bus 企业服务总线, 是连接中枢

RPC #

# 远程过程调用 remote procedure call

Thrift #

CXF #

常识
    自己内部整合spring(但是不耦合)
支持的协议
    soap1.1/1.2
    post/http
    restful
    http
使用
    导入cxf包
    方法1      # 不支持注解
        String address="http://localhost:8888/hello";
            ServerFactoryBean factoryBean=new ServerFactoryBean();
            factoryBean.setAddress(address);
            factoryBean.setServiceBean(new MyWS());
            factoryBean.create();
    方法2      # 支持注解,wsdl文件中类型不再单独schema文件
        ServerFactoryBean factoryBean = new JaxWsServerFactoryBean      # java and xml web service
    日志    # 记录握手信息(访问wsdl文件)
            ## 看日志记录得到 soap
        serverFactoryBean.getInInterceptors().add(new LoggingInInterceptor());
        serverFactoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
整合spring
    o-> cxf2.4.4.jar/schemas/jaxws.xsd中找到命名空间"http://cxf.apache.org/jaxws"
    o-> 配置applicationContext.xml,加入cxf的命名空间http://cxf.apache.org/jaxws,schema地址为http://cxf.apache.org/schemas/jaxws.xsd。
        并且在eclipse中配置schema约束文件的路径
            # 该xsd约束文件的url地址用的是包地址,不规范
    o-> applicationContext.xml中配置
        <bean id="studentService" class="test.spring.StudentServiceImpl"/>
            # 用于:自身调用,被spring引用
        <jaxws:server serviceClass="test.spring.StudentService" address="/student">
            # address配置服务的名称即可(web.xml的servlet中配置了服务的实际访问地址)
            ## serviceClass配置的才是真正的服务,既然它是接口,那么webService注解也应该写在接口上
            <jaxws:serviceBean>
                <ref bean="studentService"/>
            <jaxws:inInterceptors>
                <bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
            <jaxws:outInterceptors>
                <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
    o-> web.xml中配置servlet
         <servlet>
              <servlet-name>springWS
              <servlet-class>org.apache.cxf.transport.servlet.CXFServlet        # 在cxf-2.4.4.jar包中
              <load-on-startup>1
         <servlet-mapping>
              <servlet-name>springWS
              <url-pattern>/ws/*
    o-> web.xml中配置spring监听器

GRPC #

Protobuf #

# 通信协议
命令
    protoc -I. -I-I$GOPATH/src  --go_out=plugins=grpc:. *
        # -I import目录
    protoc --grpc-gateway_out=.
插件
    安装
        # go build 出protoc-gen-go后,放入go/bin下
    protoc-gen-go
        # 编译proto文件
    protoc-gen-grpc-gateway
        # http服务

RMI #

# java远程调用 remote method invocation

Hessian #

# 是caucho公司的开源协议,基于http

Burlap #

# caucho公房的开源协议,基于http

HttpInvoker #

# spring提供的协议,必须用spring

Web Service #

# soap通讯

粘合层 #

治理(服务发现) #

Zookeeper #

介绍
    google chubby的开源实现。用于服务发现
    保证CP
    分布式, hadoop中hbase的组件
    fast paxos算法        # paxos存在活锁问题, fast paxos通过选举产生leader, 只有leader才能提交proposer
功能
    配置维护
    域名服务
    分布式同步
    组服务
    分布式独享锁、选举、队列
流程
    选举leader        # 多种算法, leader有最高执行ID
    同步数据
    大多数机器得到响应follow leader
exhibitor
    # supervisor for zk

Eureka #

# Netflix,保证AP

Consul #

# Apache,保证CA

Etcd #

# kubernetes用,保证CP

路由控制 #

负载均衡策略
    随机、轮询、调用延迟判断、一致性哈希、粘滞连接
本地路由优先策略
    优先JVM(injvm),优先相同物理机(innative)
配置方式
    统一注册表、本地配置、动态下发

配置 #

Spring Cloud Config #

Diamond #

# 淘宝

Archaius #

# netflix

Disconf #

# 百度

QConf #

# 360

任务 #

Elastic-Job #

# 当当网

Azkaban #

# linkedin

Spring Cloud Task #

跟踪 #

zipkin #

# twitter

Opentracing #

Hydra #

# 京东

Spring Cloud Sleuth #

监控 #

Spy.js #

# webstorm用的监控工具

Alinode #

# 朴灵写的运行时性能管理工具

OneAPM #

# 监控node性能
功能
    接口响应时间
    数据库方法时间
    外部服务时间
    单请求的耗时比

容错 #

Hystrix #

功能
    服务线程隔离、信号量隔离
    降级: 超时、资源不足
    熔断: 自动降级、快速恢复
    请求缓存、请求合并

代理 #

Gearman #

# 分布式计算, 把工作委派给其他机器

Hazelcast #

# 基于内存的数据网格,用于分布式计算

Twemproxy #

redis/memcache分片代理

高可用 #

# high-availability linux
目标
    reliability: 可靠性
    availability: 可用性
    serviceability: 可服务性
        ras: remote access service(远程服务访问)
术语
    节点(node): 唯一主节点,多个备用节点
    资源(resource): 是节点可控制的实体,主节点发生故障时,可以被其它节点接管
        例如:
            磁盘分区
            文件系统
            ip地址
            应用程序服务
            nfs文件系统
    事件(event): 集群中可能发生的事件
        例如:
            系统故障
            网络连通故障
            网卡故障
            应用程序故障
    动作(action): 事件发生时ha的响应方式
        例如: 用shell 脚本对资源进行转移

心跳 #

HeartBeat #

2.0模块
    heartbeat: 节点间通信检测模块
    ha-logd: 集群事件日志服务
    CCM(Consensus CLuster Membership): 集群成员一致性管理模块
    LRM(Local Resource Manager): 本地资源管理模块
    Stonith Daemon: 使出现问题的节点从集群资源中脱离
    CRM(Cluster Resource management): 集群资源管理模块
    Cluster policy engine: 集群策略引擎
            用于实现节点与资源之间的管理与依赖关系
    Cluster transition  engine: 集群转移引擎

3.0拆分之后的组成部分
    Heartbeat: 负责节点之间的通信
    Cluster Glue: 中间层,关联Heartbeat 与 Pacemaker,包含LRM 与 stonith
    Resource Agent: 控制服务启停,监控服务状态脚本集合,被LRM调用
    Pacemaker: 也就是曾经的CRM,包含了更多的功能
        管理接口:
            crm shell
            一个使用ajax web 的web窗口
            hb_gui图形工具
            DRBD-MC, 一个基于java的工具

版本差异
    与1.x相比,2.1.x版本变化
        保留原来所有功能
        自动监控资源
        对各资源组进行独立监控
        同时监控系统负载
            自动切换到负载低的node上

Keepalived #

vrrp
    # virtual router redundancy protocol 虚拟路由器冗余协议
    # 解决静态路由出现的闪单点故障问题,它能够保证网络的不间断.稳定运行

负载 #

# load balance
方法
        dns轮循

        java nio
        erlang语言
        linux epoll
        bsd kqueue
        消息队列、事件通知
        c/c++下ace, boost.asio, libev(libevent)
        服务器mina, jetty, node.js, netty
        java协程框架 quasar kilim

Haproxy #

监控页面
        /status

Tengine #

# 淘宝基于nginx修改,添加了功能
监控
    /upstream_status

OpenResty #

# 淘宝改的nginx, lua工具
安装
    yum install -y gcc gcc-c++ kernel-devel readline-devel pcre-devel openssl-devel openssl zlib zlib-devel pcre-devel
    wget openresty-1.9.15.1.tar.gz
    ./configure --prefix=/opt/openresty --with-pcre-jit --with-ipv6 --without-http_redis2_module --with-http_iconv_module -j2
    make && make install
    ln -s /opt/openresty/nginx/sbin/nginx /usr/sbin
    /opt/openresty/nginx/conf/nginx.conf

Varnish #

# 反向代理, http缓存

Traffic Server #

# apache 缓存

Squid #

配置文件
    /etc/squid/squid.conf
代理类型
    普通代理
    透明代理
    反向代理
缓存
    动态资源
    静态资源
参考资料
    squid 透明代理详解
配置
    # squid.conf
    http_port 3128                                                # squid服务端口
    icp_port 3130                                                # udp端口,用来接收和发送ICP消息
    cache_dir ufs /var/spool/squid                                # 缓存目录, 写入方式有aufs与ufs两种,aufs使用大量线程异步进行磁盘i/o操作
    cache_access_log /var/log/squid/access.log
    cache_log /var/log/squid/cache.log
    cache_store_log /var/log/squid/store.log
    pid_filename /var/run/squid.pid                        # 日志文件位置

    #auth_param basic children 5
    #auth_param basic realm Squid proxy-caching web server
    #auth_param basic credentialsttl 2 hours                 # 关闭认证,认证一般不需要

    cache_effective_user squid
    cache_effective_group squid
    cache_mgr youraccount@your.e.mail                        # 设置squid用户及用户组、管理员账号

    cache_mem 128 MB                                        # 运行内存配置

    cache_swap_low 90
    cache_swap_high 95
    maximum_object_size 4096 KB                        # 与磁盘容量相关的配置,90、95为百分比,磁盘大时4096 KB可以改成32768 KB

    maximum_object_size_in_memory 8 KB                # 内存缓存资料大小

    以下为定义acl(访问控制列表)
            # 语法为:acl<acl> <acl名称> <acl类型> <配置的内容>
    acl All src 0/0
    acl Manager proto cache_object  acl Localhost src 127.0.0.1/32
    acl Safe_ports port 80 21 443 563 70 210 280 488 591 777 1025-65535
    acl SSL_ports 443 563
    acl CONNECT method CONNECT
    acl MyNetwork src 192.168.0.0/16

    以下为利用前面定义的acl,定义访问控制规则
    http_access allow Manager Localhost
    http_access deny Manager
    http_access deny !Safe_ports
    http_access deny CONNECT SSL_ports
    http_access allow MyNetwork
    http_access deny All

    例子: 禁止访问sina
    acl sina dstdomain .sina.com.cn .sina.com
    http_access deny sina
    或
    acl sina dst 58.63.236.26 58.63.236.27 58.63.236.28 58.63.236.29 58.63.236.30 58.63.236.31 58.63.236.32 58.63.236.33 58.63.236.34 58.63.236.35 58.63.236.36 58.63.236.37 58.63.236.38 58.63.236.39 58.63.236.49 58.63.236.50
    http_access deny sina
    或
    acl sina dst www.sina.com.cn
    http_access deny sina

    例子: 禁止来自某些ip的访问
    acl zhang src 192.168.63.6/32
    http_access deny zhang

    例子: 禁止在某些时段访问
    acl Working_hours MTWHF 08:00-17:00
    http_access allow Working_hours
    http_access deny !Working_hours

    例子: 禁止某个代理客户建立过多连接
    acl OverConnLimit maxconn
    http_access deny OverConnLimit

    定义与其它代理服务器的关系,语法: <cache_peer> <主机名称> <类别> <http_port> <icp_port> <其它参数>
    cache_peer 192.168.60.6 parent 4480 7 no-query default

    #设置与其它代理服务器的关系: <cache_peer_access> <上层 Proxy > <allow|deny> <acl名称>
    #cache_peer_access 192.168.60.6 allow aclxxx
    #cache_peer_access 192.168.60.6 deny !aclxxx
    coredump_dir /var/spool/squid                                        # 崩溃存储目录
使用
    step1 检查配置文件
        squid -k parse
    step2  初始化cache 目录
        squid -z(X)                                # X会显示过程
    step3 启动squid
        service squid start
        或
        /usr/local/squid/sbin/squid -sD
    停止squid
        squid -k shutdown
    重新载入配置
        squid -k reconfigure
    滚动日志
        squid -k rotate
案例
    透明代理
        step1 检查配置文件
            squid -k parse
        step2  初始化cache 目录
            squid -z(X)                                # X会显示过程
        step3 启动squid
            service squid start
            或
            /usr/local/squid/sbin/squid -sD
        停止squid
            squid -k shutdown
        重新载入配置
            squid -k reconfigure
        滚动日志
            squid -k rotate
    代理
        squid.conf
            http_port 3128
            http_access allow all
            或
            http_port 3128
            http_access deny all前面添加
            acl 192.168.0.42 src 192.168.0.0/24
            http_access allow 192.168.0.42                        # 192.168.0.42为允许的ip

LVS #

介绍
    第四层开始负载(可以建立到三层负载)

    第四层负载
        socket进必须连lvs

模式
    tun
        # lvs负载均衡器将请求包发给物理服务器,后者将应答包直接发给用户
    net
        # 请求和应答都经过lvs
    dr
        # 不要隧道结构的tun
使用
    DR模式 centos6
    yum install-y gcc gcc-c++ makepcre pcre-devel kernel-devel openssl-devel libnl-devel popt-devel
    modprobe -l |grep ipvs
        # 检查内核是否集成
    echo "1" > /proc/sys/net/ipv4/ip_forward
        # 开启路由转发
    安装ipvsadm
        http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.26.tar.gz
    安装keepalived
        http://www.keepalived.org/software/keepalived-1.2.7.tar.gz
        ./configure --prefix=/usr/local/keepalived

        cp  /usr/local/keepalived/etc/rc.d/init.d/keepalived        /etc/init.d/
        cp /usr/local/keepalived/etc/sysconfig/keepalived        /etc/sysconfig/
        mkdir /etc/keepalived/
        cp /usr/local/keepalived/etc/keepalived/keepalived.conf        /etc/keepalived/
        cp /usr/local/keepalived/sbin/keepalived        /usr/sbin/

        o-> 配置文件/etc/keepalived/keepalived.conf
        ! Configuration File forkeepalived
        global_defs {
        notification_email {
        test@sina.com    #故障接受联系人
        }
        notification_email_from admin@test.com  #故障发送人
        smtp_server 127.0.0.1  #本机发送邮件
        smtp_connect_timeout 30
        router_id LVS_MASTER  #BACKUP上修改为LVS_BACKUP
        }
        vrrp_instance VI_1 {
        state MASTER    #BACKUP上修改为BACKUP
        interface eth0
        virtual_router_id 51  #虚拟路由标识,主从相同
        priority 100  #BACKUP上修改为90
        advert_int 1
        authentication {
        auth_type PASS
        auth_pass 1111  #主从认证密码必须一致
        }
        virtual_ipaddress {    #Web虚拟IP(VTP)
        172.0.0.10
        }
        }
        virtual_server 172.0.0.10 80 { #定义虚拟IP和端口
        delay_loop 6    #检查真实服务器时间,单位秒
        lb_algo rr      #设置负载调度算法,rr为轮训
        lb_kind DR      #设置LVS负载均衡DR模式
        persistence_timeout 50 #同一IP的连接60秒内被分配到同一台真实服务器
        protocol TCP    #使用TCP协议检查realserver状态
        real_server 172.0.0.13 80 {  #第一个web服务器
        weight 3          #节点权重值
        TCP_CHECK {      #健康检查方式
        connect_timeout 3 #连接超时
        nb_get_retry 3    #重试次数
        delay_before_retry 3  #重试间隔/S
        }
        }
        real_server 172.0.0.14 80 {  #第二个web服务器
        weight 3
        TCP_CHECK {
        connect_timeout 3
        nb_get_retry 3
        delay_before_retry 3
            }
        }
        }

        service keepalived restart

    启动脚本 /etc/init.d/real.sh
        #description : start realserver
        VIP=172.0.0.10
        . /etc/init.d/functions
        case "$1" in
        start)
        /sbin/ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up
        echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
        echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
        echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
        echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
        echo "LVS RealServer Start OK"
        ;;
        stop)
        /sbin/ifconfig lo:0 down
        echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore
        echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce
        echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
        echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
        echo "LVS RealServer Stoped OK"
        ;;
        *)
        echo "Usage: $0 {start|stop}"
        exit 1
        esac

    o-> 开机启动
        chmod +x /etc/init.d/real.sh
        /etc/init.d/real.sh start
        echo "/etc/init.d/real.sh start" >> /etc/rc.local
    o-> 测试
        service httpd start
        echo "1" > /var/www/html/index.html
        service iptables stop
        setenforce 0
            # 关闭selinux
    o-> 其他命令
        ipvsadm -ln
            # 集群中服务器ip信息
        ip addr
            # 显示VIP当前绑定的服务器
        tail -f /var/log/messages
            # 日志

数据库 #

读写分离 #

MySQL主从复制
Haproxy + 多Slave
DRBD + Heartbeat + MySQL
MySQL Cluster

分片 #

问题
    事务
    Join
    迁移
    扩容
    ID生成
    分页
方案
    事务补偿        # 数据对账:基于日志对比、同步标准数据源
    分区            # MySQL机制分文件存储,客户端无感知
    分表            # 客户端管理分表路由
    分库
        为什么 
            单库无法承接连接数时分库,MySQL单库5千万条,Oracle单库一亿条
        策略
            数值范围
            取模
            日期
框架
    Sharding-JDBC
    TSharding
代理
    Atlas
    MyCAT
    Vitess

分布式文件系统 #

HDFS            # 批量读写,高吞吐量,不适合小文件
FastDFS         # 轻量级,适合小文件

一致性 #

CAP
    一致性
        强一致性、弱一致性(秒级),最终一致性
    可用性
    分区容错性(网络故障)
BASE
    Basically Available(基本可用),Soft state(软状态),Eventually consistent(最终一致性)
幂等性

分布式锁 #

算法
    PAXOS
    Zab
        # Zookeeper使用
    Raft
        # 三角色:Leader(领袖),Follower(群众),Candidtate(候选人)
    Gossip
        # Cassandra使用
实现方式
    数据库
        有单点问题
    缓存
        非阻塞性能好
        有锁不释放问题
        实现
            RedLock setnx
            Memcached add
    Zookeeper
        有序临时节点,集群透明解决单点问题,锁被释放,锁可重入
        性能不如缓存,吞吐量随集群规模变大而下降

一致性哈希 #

扩容映射

分布式事务 #

分类
    两阶段提交、多阶段提交
    TCC事务

Atomikos #

ID生成器 #

Snowflake算法           # Twitter
    41位时间戳+10位机器标识(比如IP,服务器名称等)+12位序列号(本地计数器)
MySQL自增ID + "REPLACE INTO XXX:SELECT LAST_INSERT_ID();"
    # Flicker
MongoDB ObjectId
    不能自增
UUID
    无序,过长,影响检索性能

前端

基础 #

AJAX
    # Asynchronous JavaScript and XML
    特点
        异步,提升了用户体验
            局部刷新
        优化传输,减少了数据和带宽
        客户端运行,承担服务器压力
    XMLHttpRequest
        # IE5首次引入
        readyState
            0 未初始化, 1 正在加载, 2 已加载, 3 交互中, 4 完成
        status      # 服务器http状态码
        responseXML     # 响应结果,表示为xml
        responseText    # 响应结果,表示为串
        open("method", url)
        send()
        abort()     # 停止当前请求

        创建
            new ActiveXObject()     # IE
            new XMLHttpRequest()        # firefox
        callback种类
            onSuccess
            onFailure
            onUninitialized
            onLoading
            onLoaded
            onInteractive
            onComplete
            onException
jsonp
    来源
        js在浏览器有同源策略(Same-Origin Policy), 只访问同一域下文件
        <script>标签没有同源策略限制
    原理
        编程时
            客户端注册callback f(), 名字传给服务器
            跨域服务器以文本方式写js函数, 并构造应传的json数据, 函数中调用f(json)
        运行时
            动态添加<script>标签, 请求跨域服务器的js函数

开发框架 #

模块化 #

bower
browserify
require.js
mod.js
        # 百度模块化开发工具
curl.js
        # amd load
sea.js
when
        # amd 加载

测试 #

vConsole    # APP HTML页面显示console按钮,打印请求参数

bigpipe #

介绍
    facebook的页面异步加载框架
    不同于ajax的http调用,需要更多的网线连接。bigpipe与当前页面共用http连接

使用
    前端
        <script src="jquery.js"></script>
        <script src="underscore.js"></script>
        <script src="bigpipe.js"></script>
        <div id="body"></div>
        <script type="text/template" id="tpl_body">
                <div><%=articles%></div>
        </script>
        <script>
        var bigpipe = new Bigpipe()
        bigpipe.ready('articles', function(data) {
                $('#body').html(_.render($('#tpl_body').html(), {articles: data}))
        })
        </script>

    服务器端
        app.get('/profile', function (req, res) {
            if (!cache[layout]) {
                    cache[layout] = fs.readFileSync(path.join(VIEW_FOLDER, layout), 'utf8')
            }
            res.writeHead(200, {'Content-Type': 'text/html'})
            res.write(render(complie(cache[layout])))
            ep.all('users', 'articles', function () {
                    res.end()
            })
            ep.fail(function(err) {
                    res.end()
            })
            db.getData('sql1', function (err, data) {
                    data = err ? {} : data
                    res.write('<script>bigpipe.set("articles", ' + JSON.stringify(data) + ');</script>')
            })
        })

    nodejs使用
        'use strict'
        var BigPipe = require('bigpipe');
        var bigpipe = BigPipe.createServer(8080, {
            pagelets: __dirname + '/pagelets',
                # 页面路径
            dist: __dirname + '/dist'
                # 静态资源路径
        });
        o-> 开启https
        var bigpipe = BigPipe.createServer(443, {
            key: fs.readFileSync(__dirname + '/ssl.key', 'utf-8'),
            cert: fs.readFileSync(__dirname + '/ssl.cert', 'utf-8')
        });
        o-> 嫁接
        var server = require('http').createServer(),
            BigPipe = require('bigpipe');
        var bigpipe = new BIgPipe(server, {options});
        bigpipe.listen(8080, function listening(){
            console.log('listening on port 8080.');
        });

        bigpipe.define('../pagelets', function done(err){
        });        # 合并pagelets, 结束后调用done
        o-> AMD 方式define,与链式编程
        bigpipe.define([Pagelet1, Pagelet2, Pagelet3], function done(err){
        }).define('../more/pagelets', function done(err){});
        # bigpipe.before来添加中间件, remove来删除中间件, disable、enable来跳过和重新启用中间件
        # bigpipe.use来引用插件
api
    BigPipe所有组件继承EventEmitter interface
功能
    pagelets
        var Pagelet = require('bigpipe').Pagelet;
                # var Pagelet = require('pagelet');
        Pagelet.extend({
                js: 'client.js',
                css: 'sidebar.styl',
                view: 'templ.jade',
                name: 'sidebar‘,            // 唯一路由路径
                get: function get(){
                        // 接收get请求时的业务逻辑
                }
        }).on(module);
                # 自动写 module.export部分来导出
        # traverse方法自动调用来递归找additional child pagelets, 要手动指定名称时手动调用

脚手架 #

yeoman
        # google和外部贡献团队合作开发,通过grunt和bower包装一个易用的工作流。由yo(脚手架), grunt(构建), bower(包管理)三部分组成

webpack #

# 介绍
        模块打包

# 命令
        npm i -g webpack
        npm i css-loader style-loader
        webpack ./entry.js bundle.js
                # --progress
                # --colors
                # --watch
                # --module-bind
                ## jade, 'css=style!css'
                webpack ./entry.js bundle.js --module-bind 'css=style!css'
                webpack
                        # use webpack.config.js
        npm i webpack-dev-server -g
        webpack-dev-server
                # --progress --colors
                # --hot 热部署
                # 启动一个express在8080端口
# 配置
    # webpack.config.js

    var webpack = require('webpack')
    var merge = require('webpack-merge')
    var path = require('path')
    var HtmlwebpackPlugin = require('html-webpack-plugin')

    var ROOT_PATH = path.resolve(__dirname)
    var APP_PATH = path.resolve(ROOT_PATH, 'app')
    var BUILD_PATH = path.resolve(ROOT_PATH, 'build')

    var baseWebpackConfig = {
            entry: {
                    app: path.resolve(APP_PATH, 'app.jsx')
            },
            output: {
                    path: BUILD_PATH,
                    filename: '[name].js',
                        chunkFilename: '[id].chunk.js',
                    publicPath: '/',
                            # 浏览器路径
            },
            devtool: 'eval-source-map',
            devServer: {
                contentBase: path.resolve(ROOT_PATH, 'build') ,
                historyApiFallback: true,
                inline: true,
                port: 3031
        }
            resolve: {
                    extensions: ['', '.js', '.vue', 'jsx'],
                        # 这样可以在js import 中加载扩展名
                    fallback: [path.join(__dirname, '../node_modules')],
                    alias: {
                            'src': path.resolve(__dirname, '../src'),
                            'assets': path.resolve(_dirname, '../src/assets'),
                            'components': path.resolve(__dirname, '../src/components')
                    }
            },
            resolveLoader: {
                    fallback: [path.join(__dirname, '../node_modules')]
            },
            module: {
                preLoaders: [
                        {
                                test: /\.jsx?$/,
                                loaders: ['eslint'],
                                include: APP_PATH
                        }
                ]
                    loaders: [
                    {
                            test: /\.vue$/,
                            loader: 'vue'
                    },
                    {
                            test: /\.js$/,
                            loader: 'babel',
                            include: projectRoot,
                            exclude: /node_modules/
                    },
                    {
                            test: /\.json$/,
                            loader: 'json'
                    },
                    {
                            test: /\.html$/,
                            loader: 'vue-html'
                    },
                    {
                            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                            loader: 'url',
                            query: {
                                    limit: 10000,
                                    name: path.posix.join('static', 'img/[name].[hash:7].[ext]')
                            }
                    },
                    {
                            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
                            loader: 'url',
                            query: {
                                    limit: 10000,
                                    name: path.posix.join('static', 'fonts/[name].[hash:7].[ext]')
                            }
                    }
                    ]
            },
        plugins: [
                    new HtmlwebpackPlugin({title: 'a'})
            ]
    }
    module.exports = merge(baseWebpackConfig, {
    })
# 插件
    内置
            # 通过webpack.BannerPlugin获得
            bannerPlugin
    htmlWebpackPlugin
    hotModuleReplacement

grunt #

介绍
        压缩js代码
        合并js文件
        单元测试
        js代码检查
        监控文件修改重启任务
命令
        grunt dist
                # 重新生成dist目录,将编译后的css,js放入
        grunt watch
                # 监测less源码文件改动,自动重新编译为css
        grunt test
                # 运行测试用例
        grunt docs
                # 编译并测试
        grunt 重新构建所有内容并运行测试用例
安装
        # grunt模块以grunt-contrib-开头
        npm i -g grunt grunt-init grunt-cli

例子
    o->
    // Gruntfile.js
    module.exports = function (grunt) {
            grunt.loadNpmTasks('grunt-contrib-clean')
            grunt.loadNpmTasks('grunt-contrib-concat')
            grunt.loadNpmTasks('grunt-contrib-jshint')
            grunt.loadNpmTasks('grunt-contrib-uglify')
            grunt.loadNpmTasks('grunt-replace')

            grunt.initConfig({
                    pkg: grunt.file.readJSON('package.json'),
                    jshint: {
                            all: {
                                    src: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
                                    options: {
                                            jshintrc: 'jshint.json'
                                    }
                            }
                    },
                    clean: ['lib'],
                    concat: {
                            htmlhint: {
                                    src: ['src/core.js', 'src/reporter.js', 'src/htmlparser.js', 'src/rules/*.js'],
                                    dest: 'lib/htmlhint.js'
                            }
                    },
                    uglify: {
                            htmlhint: {
                                    options: {
                                            banner: 'a',
                                            beautify: {
                                                    ascii_only: true
                                            }
                                    },
                                    files: {
                                            'lib/<%= pkg.name %>.js': ['<%= concat.htmlhint.dest %>']
                                    }
                            }
                    },
                    relace: {
                            htmlhint: {
                                    files: {'lib/htmlhint.js': 'lib/htmlhint.js'},
                                    options: {
                                            prefix: '@',
                                            variables: {
                                                    'VERSION': '<%= pkg.version %>'
                                            }
                                    }
                            }
                    }
            })
            grunt.registerTask('dev', ['jshint', 'concat'])
            grunt.registerTask('default', ['jshint', 'clean', 'concat', 'uglify', 'replace'])
    }

gulp #

介绍
        自动化构建项目工具
使用
    安装
            npm install --global gulp
                    # npm install --save-dev gulp
            // gulpfile.js 在项目根目录
            var gulp = require('gulp');
            gulp.task('default', function () {
                    // 默认任务代码
            })
    命令
            shell> gulp
                    # gulp <task> <othertask>
插件
    gulp-dom-src
            合并src, 改写html
    gulp-if
    gulp-useref
    gulp-usemin
    gulp-htmlreplace
    google-closure-compiler
    gulp-add-src
    gulp-autoprefixer
    gulp-changed
    gulp-clean
    gulp-clean-css
    gulp-concat
    gulp-concat-css
    gulp-consolidate
    gulp-html-replace
            # 替换html内容
    gulp-htmlmin
    gulp-imagemin
    gulp-less
    gulp-make-css-url-version
    gulp-minify-css
    gulp-rev-append
    gulp-uglify

fis #

介绍
        npm的形式发布
        百度前端工具框架,为前端开发提供底层架构
        所有js文件都用模块书写,一个文件一个模块
                F.module(name, function(require, exports){}, deps);

安装
        npm install -g fis
命令
    fis install                        # 安装模块
    fis release                        # 编译和发布, -h 查看帮助
                            ## 默认会调整资源引用的相对路径到绝对路径
                            ### 不想对路径做调整,可以使用spt工具https://github.com/fouber/spt
                            ## --optimize 或 -o 压缩。--md5对不同静态资源生成版本,也可以配置时间戳
                            ## --dest 或 -d。指定项目发布配置,在执行编译后发布。可以远程发布、发布多个
                            ## --pack 开启打包处理
                            ## -omp 简化 --optimize --md5 --pack
                            ## --watch 或 -w 自动监听文件修改,自动编译
                            ### 该监视考虑了各种嵌入关系, a.css中嵌入了b.css, b修改时会重构这两个文件
                            ### --live 或 -L 。在-w基础上实现,监视到修改后自动刷新浏览器页面
    fis server start                # 启动本地调试服务器
                            ## -p [port] 指定新端口
                            ## --type node 如果没有java, php环境,指定用node环境启动
    fis server stop
    fis server open                # 查看默认产出目录
配置
    o->
    fis.config.set('pack', {
            'pkg/lib.js': [
                    '/lib/mod.js',
                    '/modules/underscore/**.js',
                    'modules/backbone/**.js'
            ]
    });                # 文件合并成lib.js,但是不替换页面中的静态资源引用
                    ## 为了替换引用,使用fis的后端静态资源管理来加载引用,或者用fis-postpackager-simple插件
    o->
    fis.config.set('roadmap.path', [{
            reg: '**.css',
            useSprite: true
    }]);                # 为所有样式资源开启csssprites, 该插件在fis中内置
    fis.config.set('settings.spriter.csssprites.margin', 20);                # 设置图片合并间距
                                                    ## 要在要合并的图片引用路径后面加?__sprite来标识
                                                    ## 被合并图片中的小图, background-position来分图的情况也支持
组件
    yogurt
        基于express 的nodejs框架
    fis-plus
        fis + php + smarty
    gois
        fis + go + margini
    jello
        fis + java + velocity
    pure
        纯前端框架

插件
    fis-postpackager-simple
        介绍
                fis-plus和yogurt不需要
        安装
                npm install -g fis-postpackager-simple
        配置
                // fis-conf.js
                fis.config.set('modules.postpackager', 'simple');                        # 打包时自动更改静态资源引用
                fis.config.set('settings.postpackager.simple.autoCombine', true)        # 开启按页面自动合并css, js文件
    fis-parser-less
        介绍
                less模板
                npm install -g fis-parser-less
        配置
                fis.config.set('modules.parser.less', 'less');
                        # 'modules.parser.less'表示后缀名less的文件,'less'表示用fis-parser-less编译
                fis.config.set('roadmap.ext.less', css)
                        # 将less文件编译为css

写法 #

jquery
prototype
    $()     # 简写document.getElementById()
    $F()    # 返回表单
    $A()    # 参数转成数组对象
mootools
    # 浏览器原生对象扩展
underscore
    # 函数式
underscore-contrib
    # 扩展underscore
ramda
    # 函数式,较正确
lodash
    # 函数式
functional javascript
bilby
    # 函数式库,包含dispatch, 蹦床, monadic, validator等
allong.es
    # 提供函数组合子
sweet
    # 支持宏
zepto
    # 小型jquery
kissy
    # 小型jquery
rxjs
    # 微软开发,将异步流捕获成值的库
tangram
    # 百度前端工具集
qwrap
    # 360前端工具集

解释器 #

typescript
    # 扩展语言
coffeescript
    # 扩展语言
system.js
    介绍
        一个垫片库, 浏览器端l加载es6模块、AMD模块、CommonJS模块 到es5。内部调用traceur

    <script src='system.js'></script>
    <script>
        System.import('./app').then(function(m) {
            # app.js是一个es6模块
            m.f()
        })
    </script>
traceur
    介绍
        在线转换,将ES6代码编译为ES5
    使用
        npm install -g traceur
        traceur /path/es6                                # 运行ES6文件
        traceur --script /path/es6 --out /path/es5        # 转换
babel
    使用
        npm install -g babel-cli
        npm install --save babel-core babel-preset-es2015
        // .babelrc
        {
            "presets": ["es2015"],
            "env": {
                "dev": {
                    # 在NODE_ENV=dev时使用特性
                    "presets": ["react-hmre"]
                }
            }
        }
        babel-node
        babel es6.js
            # babel es6.js -o es5.js
            # babel -d build source -s
            ## -s 是产生source-map
    插件
        babel-preset-react-hmre
            # react热加载
            .babelrc中配置 "react-hmre"
transpiler
    介绍
        google的es6模块加载转为CommonJS或AMD模块加载的工具
    使用
        npm install -g es6-module-transpiler
        compile-modules convert es6.js es5.js
            # compile-modules convert -o out.js file1.js

数据绑定 #

mobx
    # 状态管理,应用(ui, 数据, 服务器)状态可自动获得

终端 #

跨平台 #

atom electron
node-webkit
atom-shell
nw.js
polymer
    # 构建在底层的html扩展,构建跨desktop, mobile等平台的web应用
mpx
    # 小程序框架
wepy
    # 小程序
taro
    # 生成多端
chameleon
uniapp
    # vue到多端
mpvue
    # vue小程序
megalo
    # vue小程序

运行时跨平台 #

微信小程序
华为快应用
react native
rax
weex
fuse
nativeScript
tabris

android #

结构
    applications:                                                        如browser
    application framework(相当于api):                        如window manager
    libraries(库):                                                        如openGL,SQLite
            runtime(运行环境):                                                core libraries + Dalvik VM
    linux kernel(系统api):                                        如wifi Driver
android sdk
    命令
        platform-tools/adb
            adb install *.apk                                      # 当前模拟器中安
    装软件

            adb remount
            adb shell
            su                                                      # 当前模拟器中执
    行linux命令

        tools/emulator-arm @test                                    # 启动一个模拟器
框架
    atlas
        # 阿里开源的android native容器化组件框架
    webview
    litho
        # 声明式ui
    jetpack compose
        # 声明式ui

ios #

componentKit
    # 声明式ui

功能 #

格式 #

uglifyjs2
    # 序列化

模板 #

介绍
    引擎的一个优点就是可以直接把数据渲染到js中使用
优点
    可以把动态页面的模板缓存起来,第一次请求之后,只需要更新数据
        # 应该可以后端nginx缓存静态模板来提高性能

velocity
    # java模板
ejs
hogan.js
handlebars
    # 写法类似anglarjs模板
jstl
    # java模板
less
    # css模板
stylus
    # css模板

swig #

{% autoescape true %} {{ myvar }} {% endautoescape %}

{% block body %} ... {% endblock %}

{% if false %}
{% elseif true%}
{% else %}
{% endif %}

{% extends "./layout.html" %}

{% filter uppercase %} oh hi, {{ name }} {% endfilter %}                # => OH HI, PAUL
{% filter replace(".", "!", 'g") %} Hi. My name is Paul. {% endfilter %}        # => Hi! My name is Paul!

{% for x in obj %}
        {% if loop.first %}<ul>{% endif %}
        <li>{{ loop.index }} - {{ loop.key }}: {{ x }}</li>
        {% if loop.last %}</ul>{% endif %}
{% endfor %}
{% for key, val in arr|reverse %}
{{ key }} -- {{ val }}
{% endfor %}

{% import './formmacros.html' as forms %}
{{ form.input("text", "name") }}                        # => <input type="text" name="name">
{% import "../shared/tags.html" as tags%}
{{ tags.stylesheet('global')}}                        // => <link rel="stylesheet" href="/global.css">

{% include "./partial.html" %}
{% include "./partial.html" with my_obj only%}
{% include "/this/file/does/not/exist" ignore missing%}

{% macro input(type, name, id, label, value, error)%}
        <label for="{{ name }}">{{ label }}</label>
        <input type="{{ type }}" name="{{ name }}" id="{{ id }}" value="{{ value }}" {% if error%} class="error" {% endif %}>
{% endmacro %}
{{ input("text", "fname",  "fname", "First Name", fname.value, fname.errors) }}

{% extends "./foo.html" %}
{% block content %}
        My content
        {% parent %}
{% endblock %}

{% raw %}{{ foobar }}{% endraw %}

{% set foo = "anything!"%}
{{ foo }}

{% spaceless %}
        {% for num in foo %}
        <li>{{ loop.index }}</li>
        {% endfor %}
{% endspaceless %}                                # 除去空白

显示 #

highcharts
nvd3.js
    # svg报表
echarts

d3 #

介绍
    数据可视化, 使用svg, css3
使用
    node
        npm install d3
        //
        var d3 = require('d3'), jsdom = require('jsdom');
        var document = jsdom.jsdom(),
            svg = d3.select(document.body).append('svg');
    web
        <script src="//d3js.org/d3.v3.min.js"></script>
        <script>d3.version</script>
d3对象
    // 选择器
    event
    mouse
    select
    selectAll
    selection
    touch
    touches
    // 过渡
    ease
            # ease对象
    timer
            flush
    interpolate
            # interpolate对象
    interpolateArray
    interpolateHcl
    interpolateHsl
    interpolateLab
    interpolateNumber
    interpolateObject
    interpolateRgb
    interpolateRound
    interpolateString
    interpolateTransform
    interpolateZoom
    interpolators
    transition
    // 数组
    ascending
    bisectLeft
    bisector
    bisectRight
    bisect
    descending
    deviation
    entries
    extent
    keys
    map
    max
    mean
    median
    merge
    min
    nest
    pairs
    permute
    quantile
    range
    set
    shuffle
    sum
    transpose
    values
    variance
    zip
    // 数学
    random
    transform
    // 请求
    csv
    html
    json
    text
    tsv
    xhr
    xml
    // 格式化
    format
    formatPrefix
    requote
    round
    // 本地化
    locale
    // 颜色
    hcl
    hsl
    lab
    rgb
    // 命名空间
    ns
    // 内部
    dispatch
    functor
    rebind
    // 比例尺
    scale
    // 时间
    time
    // 布局
    layout
    // 地理
    geo
    // 几何
    geom
    // 行为
    behavior

效果 #

touch.js
    # 触摸
move.js
    # div运动
swiper
    # 滑动效果

cordova
    # 访问原生设备,如摄像头、麦克风等
egret.js
    # 使用TypeScript的HTML5开发引擎, 一套完整的HTML5游戏开发解决方案
tweenMax
    # 扩展TweenLite, 用于制作html5动画
juliusjs
    # 语音识别
babylon
    # microsoft webgl框架
cubicVR
    # 高性能webgl框架, paladin游戏引擎的一部分
scenejs
    # webgl模型
glge
    # webgl框架
pose
    # mvvm
react-motion
    # mvvm
react-transition-group
    # mvvm

视频 #

ezuikit
    # 萤石sdk, 直播, 监控, 支持多平台

应用框架 #

显示 #

bootstrap
flutter
    # google移动端框架, 声明式ui
extjs
    介绍
        2.0之前是免费的,但有内在泄漏总是
        GPLv3版本后收费

    Sencha
        1.是ExtJS、jQTouch(一个用于手机浏览器的jquery插件) 以及 Raphael(一个网页上绘制矢量图形的js库) 三个项目合并而成的一个开源项目。
        2.Sencha Touch 是全球领先的应用程序开发框架,其设计旨在充分
            利用HTML5、CSS3 和Javascript 来实现最高级别的功能、灵活性和优化。
            Sencha Touch 是针对下一代具有触摸屏设备的跨平台框架。
jquery ui
dojo
    # 语法较难用
easy ui
    文件
        jquery.js
        easyui.js
        easyui-lang-zh_CN.js
        easyui.css
        icon.css
layui
    # 模块化ui
mini ui
    # 收费
wijmo
    # 收费
dwz
    # 卖文档
vaadin
    # apache webkit
foundation
    # 响应式,移动优先
boilerplate
    # h5模板
meteor
    # 融合前后端, 后端node
knockout
    # mvvm, 利于单页应用

jingle
    # 手机
ionic
    # angular手机框架
framework7
    # ios(兼容android)组件
mui
    # 手机
zui
    # 手机,类bootstrap
frozenui
    # 手机

数据可视化 #

highcharts
chart.js
    # api不好用
three.js
d3
    # 太底层, 概念已陈旧
mapbox
    # 地图
echarts
    # 开源
recharts
    # 新出现
v-charts
    # vue+echarts, 饿了么开发
superset
    # apache
antv
    # 蚂蚁金服, 图表丰富
thingJS
    # 3d建模
cityBuilder
    # 3d建模
dataV
    # 收费, 阿里
sugar
    # 收费, 百度
云图
    # 收费, 腾讯
fineReport
    # 收费, 帆软, 大屏
tableau
    # 收费, 大屏
easyV
    # 收费, 袋鼠云

gitDataV
    # https://github.com/HongqingCao/GitDataV

富应用 #

react
angular
    # google开发, mvvm
    ng(core module)包含的核心组件
        directive   # 指令
            ngClick
            ngInclude
            ngRepeat
        service     # 服务, 依赖注入后使用
            $compile
            $http
            $location
        filter      # 过滤器,转换模板数据
            filter
            date
            currency
            lowercase
        function    # 函数
            angular.copy()
            angular.equals()
            angular.element()
    组件
        ngRoute     # url后#地址(hash) 来实现单面路由
            使用
                引入angular-route.js
                依赖注入ngRoute模块
            服务
                $routeParams    # 解析路由参数
                $route          # 构建url, view, controller的关系
                $routeProvider  # 配置
            指令
                ngView      # 路由模板插入视图
        ngAnimate   # 动画效果
            使用
                引入angular-animate.js
                注入ngAnimate
            服务
                $animate    # 触发
            css动画   # 用nganimate结构定义,通过引用css到html模板触发
            js动画    # 用module.animation注册,通过引用css到html模板触发
        ngResource  # 动画
        ngMock      # 动画
        ngTouch     # 触摸
        ngAria      # 帮助制作自定义模块
        ngCookies
riot
ember
vue
    <div id="app">
        {{ message }}
    </div>

    var app = new Vue({
        el: '#app',
        data: {
            message: "hi"
        },
        created: function () {}
    })
backbone

效果 #

three.js

createjs #

# easeljs
    介绍
        处理canvas
    使用
        var stage = new createjs.Stage("canvasName");
        stage.x = 100;
        stage.y = 100;
        var text = new createjs.Text("Hello", "36px Arial", "#777");
        stage.addChild(text);
        stage.update();
# tweenjs
    介绍
        处理动画调整和js属性
    使用
        var circle = new createjs.Shape();
        circle.graphics.beginFill("#FF0000").drawCircle(0, 0, 50);
        stage.addChild(circle);
        createjs.Tween.get(circle, {loop: true})
            .wait(1000)
            .to({scaleX: 0.2, scaleY: 0.2})
            .wait(1000)
            .to({scaleX:1, scaleY:1}, 1000, createjs.Ease.bounceInOut)
        createjs.Ticker.setFPS(20);
        createjs.Ticker.addEventListener("tick", stage);
# soundjs
    介绍
        简化处理音频
    使用
        var displayStatus;
        displayStatus = document.getElementById("status");
        var src = "1.mp3";
        createjs.Sound.alternateExtensions = ["mp3"];
        createjs.Sound.addEventListener("fileload", playSound());
        createjs.Sound.registerSound(src);
        displayStatus.innerHTML = "Waiting for load to complete";

        function playSound(event){
            soundIntance = createjs.Sound.play(event.src);
            displayStatus.innerHTML = "Playing source: " + event.src;
        }

# preloadjs
    介绍
        协调程序加载项的类库
    使用
        var preload = new createjs.LoadQueue(false, "assets/");
        var plugin= {
            getPreloadHandlers: function(){
                return{
                    types: ["image"],
                    callback: function(src){
                        var id = src.toLowerCase().split("/").pop().split(".")[0];
                        var img = document.getElementById(id);
                        return {tag: img};
                    }
                }
            }
        }
        preload.installPlugin(plugin);
        preload.loadManifest([
            "Autumn.png",
            "BlueBird.png",
            "Nepal.jpg",
            "Texas.jpg"
        ]);

游戏 #

cocos2dx
    # 跨平台游戏

小功能

名词 #

dom                文档对象模型
dao                数据访问对象
ucs                unicode character set
utf                ucs Transformation Format
bmp                Basic Multilingual plane
bom                Byte Order Mark
asp                Active Server Pages
iis                Internet Information services
validate code                 验证码
tld                 tag library description
jsp                 java server page
xsd                XML Schemas Definition
suffix              后缀
ide                Integrated Development Environment
RIA                Rich internet Applications                富互联网应用(富客户端)C/S架构是胖客户端,B/S架构是瘦客户端。比如 flash就是ria(其它如js, SilverLight,unity3d,flash3d,adobe air,HTML5/css3,adobe Flex等)
JPA                Java Persistence API                        java持久层api
JDBC                Java DataBase Connectivity
DHTML                DynamicHTML
cvs                Concurrent Version System
svn                subversion
uml                UnifiedModelingLanguage
AJAX            Asynchronous JavaScript and XML
bnf                命令书写格式规范: 巴科斯范式
desc            description
capacity        容量
component       组件
association         联合
aggregation         聚合
composition         组合
alpha           开端
inherit         继承
dhtml           dynamic html ,是 html css 客户端script                        不是规范,是现有技术、标准的整合运用
css             Cascading Style Sheet   级联样式表
associated                交互的
perspective                视图
adapter         适配器
jit             just in time (compilation)
webdav          Web-based Distributed Authoring and Versioning        Web 分布式创作和版本管理 (WebDAV) 扩展了 HTTP/1.1 协议,允许客户端发布、锁定和管理 Web 上的资源
CMS             Content Management System        内容管理系统        它具有许多基于模板的优秀设计,可以加快网站开发的速度和减少开发的成本。
constraint      约束
JSON            javascript object notation(标记)
OGNL            Object-Graph Navigation Language 对象图导航语言
jmf               java media frame java 媒体框架 是一个jar 包
dwr                Direct Web Remoting 是一个ajax框架。它可以允许在浏览器里的代码使用运行在WEB服务器上的JAVA函数,就像它就在浏览器里一样。
CXF                 apache的 Celtix + XFire,用于实现 web services的发布的使用
oa                Office Automation 办公自动化
dml                data manipulation language        数据操作语言
ddl                data definition language        数据定义语言
dcl                data control language                数据控制语言
ioc                inversion of control        控制反转(spring)
di                 dependence injection        依赖注入 (spring)
crud               增加(Create)、查询(Retrieve)(重新得到数据)、更新(Update)和删除(Delete)
ssh                Secure Shell,由IETF制定,为建立在应用层和传输层基础上的安全协议。
pojo                pure old java object
oop                object oriented programming
aop                aspect oriented programming                面向切面编程
hdfs                Hierarchical Data Format        层次型资料格式(分布式存储)
ftp                File Transfer Protocol
ssl                Secure Sockets Layer 安全套接层。端口40
tls                Transport Layer Security 传输层安全(ssl的继任者)
https            Hypertext Transfer Protocol Secure 应用ssl作为应用层子层对数据进行压缩与解压。端口443
jsf                JavaServer Faces 是sun开发的web框架,相当于ssh(spring + struts + hibernate)
sns                Social Network Services        社会性网络服务
uml                Unified modeling language 统一建模语言
jta                java transaction api (hibernate中) java事务处理api
asm                Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。
                    汇编语言(Assembly Language)的扩展名
jsr                Java Specification Requests 是Java规范请求,是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。jsr303:基于注解的java bean 验证
dto                data transfer object 数据传输对象
antlr             another tool for language recognition        一个开源的语法分析器
soap              simple object access protocol 简单对象访问协议
uefi              unified extensible firmware interface 统一可扩展固件接口
sso                single sign on 单点登录
erp                enterprise resource plan 企业资源计划
sap                Systems Applications and Products in Data Procession 企业系列软件(全世界排名第一的erp软件)
ssi                Server Side Include 服务器端嵌入
jmx                Java Management Extensions java管理扩展,是一个为应用程序、设备、系统等植入管理功能的框架。
jaas                Java Authentication Authorization Service Java验证和授权API
jca(J2C, J2CA)        Java Connector Architecture java连接器架构
jms                    Java Message Service java消息服务,用于在两个应用程序之间,或分布式系统中发送消息
jaf                    JavaBeans Activation Framework JAF是一个专用的数据处理框架,它用于封装数据,并为应用程序提供访问和操作数据的接口。JAF的主要作用在于让java应用程序知道如何对一个数据源进行查看、编辑和打印等操作。
jta                    Java Transaction API Java事务API,和jts为J2EE平台提供了分布式事务服务
jts                    Java Transaction Service java事务服务
scm                    Supply chain management 一种集成的管理思想和方法,执行供应商到最终用户的物流计划控制职能
ctr                    click-through-rate 网络广告
ioc/di                    inversion of control/ dependency injection
o2o                    online to offline 网站提供平台, 用户线下交易
cas                    central authentication service 单点登录
foobar                FTP Operation Over Big Address Records(RFC1545文档)ftp命令列表
modular              模块化
enumeration         计数
navigate            导航
fragment             碎片
posix                可移植的
intersection        截断
categories          类别
encounter           遭遇
recursion           递归
evaluate            评价
indent                缩进
collation         校对
schema              模式、图表
generate            生成
Presentation         描述
hierarchical         垂直分层
stereotype         策略
numerous            许多
KISS                keep it simple, stupid
cross-origin         跨域
CORS             Cross-Origin Resourse Sharing
NIH             not invented here 自己造轮子
mis                 management information system
crm                 customer relationship management
erp             enterprise resource planning
webRTC          web Real-Time Communication

#

日志 #

log4j
    # java
logback
    # log4j后续版本
slf4j
    # java
log4js
    # js

格式|模板 #

moment
    # js格式化时间
iconv
    # nodejs调用c++ libiconv库来转码
iconv-lite
    # nodejs实现的转码,比调用c++ 的iconv更高效
poi
    # java 文件处理
jFreeChart
    # java图表库
jackson
    # java json序列化
json-smart
    # java json
xstream
    # java xml序列化
pango2
    # 国际化模板
snakeyaml
    # java yaml
js-beautify
    # js, html格式化
xmlbeans
    # java xml
joda-time
    # java日期
dom4j
    # java dom 

生成|压缩|加密|计算特征 #

simhash
    # google 文档hash
pygments
    # python 生成高亮html
mako
    # python 模板
jinja2
    # python 模板
freemarker
    # java 模板
proguard
    # java 混淆
snappy
    # google java 压缩
jbcrypt
    # java加密, scrypt更强

客户端|邮件 #

javamail
    # java mail
nodemailer
    # node mail
mailapi
    # java mail
c3p0
    # java rds 连接池
dbcp
    # java rds 连接池
druid
    # java rds 连接池。可监控sql执行性能,记sql日志
jdbc
    # java rds client
dbutil
hibernate
ef
    # .net orm
NHibernate
    # .net orm
peewee
    # python orm
node-mysql
mongoose
httpClient
    # java http
request
    # js http
superagent
    # js http
mybatis
hsqldb
    # java内置, 单文件/内存数据库
mqttv
    # java mqtt客户端
libthrift
    # java thrift
kafka-clients

领域语言 #

lex
    # 生成词法分析程序
yacc
    # 生成自底向上语法分析程序
antlr

图形 #

ccap
    # 基于c++的图形CImg库,就是一个CImg.h文件
canvas
    # node canvas
tesseract
    # node 验证码

运维控制 #

later
    # nodejs corntab
glob
    # nodejs 匹配获得文件
rd
    # node 遍历文件
commander
    # node制作命令
mkdirp
    # node 递归makedir
fs-extra
    # node扩展fs包
testcontainers
    # java, 运行docker
jOptSimple
    # java, 命令解析

协议 #

spring-websocket
    # java
httpcore-nio
    # java
grpc-context
    # java

高可用 | 性能 #

retry
    # js retry
ehcache
    # 缓存
tagg
    # node线程池
cluster
    # node单机集群
fiber
    # node协程
driud
    # 连接池,阿里开源

akka #

# scala并发、分布式、容错工具
使用
    system = ActorSystem.create("hello")
    system.actorOf() ## 前端 ### dwr
介绍
    java函数通过ajax映射到前端js调用
使用
    ajax框架
    1.导入jar包 dwr.jar
    2.web-inf/下的配置文件
        web.xml文件
            <servlet>
                <servlet-name>dwr-invoker</servlet-name>
                <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
                        # 固定写法
                <init-param>
                        <param-name>debug</param-name>
                        <param-value>true</param-value>
                </init-param>
                <init-param>
                        <param-name>scriptCompressed</param-name>        # 允许在javascript中执行
                        <param-value>false</param-value>
                </init-param>
                <load-on-startup>1</load-on-startup>        # web工程启动时加载
            </servlet>
            <servlet-mapping>
                <servlet-name>dwr-invoker</servlet-name>
                <url-pattern>/dwr/*</url-pattern>
            </servlet-mapping>
        dwr.xml文件
            <dwr>
                <allow>
                    <create creator="new" javascript="DWRUserAccess">        # 生成js文件的名(页面中引用)
                            <param name="class" value="outrun.dwr.DWRUserAccess" />                # 曝露的类
                    </create>
                    <convert converter="bean" match="outrun.dwr.User" />        # 注册实体类,可以在js中进行实例化
                </allow>
            </dwr>
    3.写outrun.dwr.DWRUserAccess中的方法
    4.页面调用
        test.html
            <script src="/outrun/dwr/engine.js"></script>
            <script src="/outrun/dwr/util.js"></script>
            <script src="/outrun/dwr/interface/DWRUserAccess.js"></script>
            <SCRIPT LANGUAGE="JavaScript">
                DWRUserAccess.方法(参数,执行完运行的js函数)
                    # 参数可以是一个map,如
                        var userMap = {};
                        userMap.id = regForm.id.value;
                        userMap.password = regForm.password.value;
                        userMap.name = regForm.name.value;
                        userMap.email = regForm.email.value;
                        DWRUserAccess.save(userMap, saveFun);
                                # 其中的regForm是页面中的表单(的name属性,dom支持直接使用名字引用表单)
            </SCRIPT>

开发 #

脚手架 #

spring boot #

drapWizard #

# java,类spring boot

写法 #

traits-decorator
    # js mixin
q
    # js 流程控制
co
    # js generator to async
async
    # js 流程控制
thunkify
    # js函数Thunk化, 确保回调调用一次
step
    # async轻量库
wind
    # js定义的宏
streamline
    # 基于源代码编译来实现流程控制简化
eventproxy
    # js event回调
spring
    # java ioc
guice
# google的java ioc轻量框架
castle
    # .net ioc
spring.net
    # .net ioc
anko
    # go 代码解释器
antlr
    # java dsl
aopalliance
    # java aop

ejb #

特点
    分布式,j2ee一部分

组成
    会话bean(session)
    实体bean(entity)
    消息驱动bean(message driven)

语言增强 #

guava #

# google工具集
maven
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
    </dependency>
组件
    o-> 增强
    Optional                            # null处理
    Preconditions                       # 准入检查
    Ordering
    Throwables

    o-> 集合
    Multiset                            # 存重复元素
    Multimap                            # 多值
    BiMap                               # 双向映射
    Table                               # 两键一值
    Range                               # 连续值
    
    o-> 字符串
    Joiner
    Spilter
    CharMatcher
    CaseFormat

    o-> 类型
    Objects
    Bytes
    Shorts
    Ints
    Longs
    Floats
    Doubles
    Chars
    Booleans

    o-> 数学
    IntMath
    LongMath
    BigIntegerMath

    o-> 高可用
    LoadingCache                        # 堆内缓存

接口 #

luavit
    # lua实现, 类node
scotty
    # haskell
webapi
    # .net
meteor.js
    # 基于node.js + mongodb的网站开发平台,把这个基础构架延伸到浏览器端, 本地和远程数据通过DDP(Distributed Data Protocol)协议传输
restify
    # 基于nodejs的rest应用框架,去掉express中的 template, render等功能, 提供DTrace功能,方便调试
ssh
    # java
spring site
    # spring整合
tapestry
    # 基于servlet的mvc框架
jersey
    # java restful服务
naga
    # java nio
echo
    # go
beego
    # go
gorilla
    # go
gin
    # go,类express
iris
    # go, fasthttp的一种实现
tornado
    # python nio
web.py
twisted
    # event driven
flask
django
bottle
    # python wsgi
rails
    # ruby的web mvc开发框架
ror
    # ror(ruby on rails)
sinatra
    # 微型web
grape
    # 运行在rack或rails/sinatra配合使用的restful风格的ruby微框架
yii
    # php
laravel
    # php
codelgniter
    # php

RESTful #

connect #

介绍
    nodejs处理http中req、res的中间件框架
    中间件分类
        pre-request用来改写request原始数据
        request/response功能各异
        post-response全局异常处理,改写response数据等
内置中间件介绍
    logger
    csrf
    compress             # gzip压缩
    basicAuth            # basic认证
    body parser          # 请求内容解析
    json
    urlencoded           # application/x-www-form-urlencode请求解析
    multipart            # multipart/form-data请求解析
    timeout
    cookieParser
    session
    cookieSession
    methodOverride       # http伪造
    responseTime         # 计算响应时间
    staticCache          # 缓存
    directory            # 目录列表
    vhost                # 虚拟二级域名映射
    favicon
    limit                # 请求内容大小限制
    query                # url解析
    errorHandler         # 错误处理
使用
    var connect = require('connect');
    var app = connect()
        .use(connect.logger('dev'))
        .use(function(req, res){
            res.end('hello world\n');
        })
        .listen(3000);

express #

安装
    npm install -g express-generator
    npm install express -d                        # g代表安装到NODE_PATH的lib里面, d代表关联套件一起安装
cookie-parser
    使用
        var cookieParser = require('cookie-parser');
        app.use(cookieParser());

        JSON.stringify(req.cookies);
        req.cookies.yourCookie
cookie-session
    使用
        var cookieSession = require('cookie-session');
        app.use(cookieSession())
        req.session = null

express-session
    options可选参数
        name                        # 表示cookie中保存session的字段名称,默认为connect.sid
        store                        # session的存储方式,默认存放在内存中,也有redis、mongodb、等模块支持
        secret                        # 设置secrect来计算hash放在cookie中产生signedCookie,来防篡改
        genid                        # 规定产生一个新的session_id时所用的函数,默认用uid2这个包
        rolling                        # 每个请求都重新设置一个cookie,默认为false
        resave                        # 即使session没有被修改,也保存session的值
    使用
        var session = require('express-session');
        app.use(session(options));

connect-redis
    使用
        var express = require('express');
        var session = require('express-session');
        var redisStore = require('connect-redis')(session);

        app.use(session({
            store: new redisStore(),
            secret: 'somesecrettoken'
        }));
serve-static
    # 静态文件
passport
    介绍
        登录验证中间件
        支持connect express sails等web框架
        支持Basic, Digest, OAuth(1.0和2.0的三种实现), Bearer等
    安装
        npm i passport
        npm i passport-local
    o-> 配置
    var express = require('express');
    var cookieParser = require('cookie-parser');
    var session = require('express-session');
    var flash = require('express-flash');
    var passport = require('passport');

    ...

    app.use(cookieParser());
    app.use(session({...}));
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(flash())

    passport.serializeUser(function (user, done) {
            done(null, user.id)
    })
    passport.deserializeUser(function (id, done) {
            User.findById(id, function (err, user) {
                    done(err, user)
            })
    })

    app.post('/login', passport.authenticate('local', {
            # passport.authenticate是个登录中间件,通过就走后面回调,否则返回401
            # local是自定义的名称
            successRedirect: '/',
            failureRedirect: '/login',
            failureFlash: true,
    }, function (req, res) {
            res.redirect('/users/' + req.user.username)
    }))

    app.post('/login', passport.authenticate('local', function(err, user, info) {
            if (err) return next(err)
            if (!user) {
                    req.flash('errors', {msg: info.message})
                    return res.redirect('/login')
            }
            req.logIn(user, function (err) {})
    })(req, res, next))
    app.get('/logout', function(req, res) {
            req.logout()
            res.redirect('/')
    })
    app.get('/user', isAuthenticated, getUser)
    var isAuthenticated = function (req, res, next) {
            if (req.isAuthenticated()) {
                    return next()
            }
            res.redirect('/login')
    }


    o-> local验证
    var LocalStrategy = require('passport-local').Strategy
    passport.use(new LocalStrategy(
            function(username, password, done) {
                    User.findOne({username: username}, function(err, user) {
                            if (err) {return done (err)}
                            if (!user) {return done(null, false, {message: 'no user'})}
                            if (!user.validPassword(password)) {...}
                            return done(null, user)
                    })
            }
    ))

    o-> usernameField
    passport.use(new LocalStrategy({
            usernameField: 'email',
            passwordField: 'passwd'
    }, function (username, password, done) {...}
    ))

    o-> OAuth
    介绍
        第三方登录协议
        三个步骤
            1. 获取未授权的request token
            2. 获取用户授权的request token
            3. 用授权的request token换取access token
    使用
        网页上申请开发github应用
        npm install passport-github
            # 安装passport的github扩展
        // app.js
        passport.use(new GithubStrategy({        // 增加github认证策略
            clientID: 'XXXX',
            clientSecret: 'YYYY',        // 已从github上申请
            callbackURL: 'http://localhost:3000/auth/github/callback'
        }, function(accessToken, refreshToken, profile, done){
            done(null, profile);
        }));
        // 定义路由
        app.all('/github', isLoggedIn);
        app.get('/github', user.github);
        app.get('/auth/github', passport.authenticate('github', {scope: 'email'}));
        app.get('/auth/github/callback', passport.authenticate('github', {
            successRedirect: '/github',
            failureRedirect: '/'
        }));
kraken
    介绍
        基于express之上的基于设置结构化代码工具
    功能
        post请求_csrf验证

    基本用法
        'use strict'
        var express = require('express'),
            kraken = require('kraken-js');
        var app = express();
        app.use(kraken());
        app.listen(8000);

koa #

介绍
    express原班人马打造的,更小,更健壮,更有表现力的web框架
    免除重复繁琐的回调函数嵌套,提高错误处理效率
    不绑定任何中间件,只是提供一个轻量优雅的函数库
    >=node0.11.16
配置
    app.name              # 应用名称
    app.env                  # 执行环境,默认是NODE_ENV 或 'development'
    app.proxy              # 决定哪些proxy header被加到信任列表中
    app.subdomainOffset      # 被忽略的.subdomains列表
    app.jsonSpaces          # 输出json时是否填充空格
    app.outputErrors        # 是否输出错误堆栈(err.stack)到stderr(app.env是'test'时,此值为false)

使用
    $ npm install koa
    $ node --harmony app.js                        # 必需使用harmony模式运行程序
    var koa = require('koa');
    var app = koa();
    app.use(function *(){
        this.body = 'Hello World';
    });        # function*  声明的generator function支持yield
               ## yield是ES6定义的新语法
    app.listen(3000);
使用(downstream & upstream)
    var koa = require('koa');
    var app = koa();

    // x-response-time
    app.use(function *(next){
    // (1) 进入路由
    var start = new Date;
    yield next;
    // (5) 再次进入 x-response-time 中间件,记录2次通过此中间件「穿越」的时间
    var ms = new Date - start;
    this.set('X-Response-Time', ms + 'ms');
    // (6) 返回 this.body
    });

    // logger
    app.use(function *(next){
    // (2) 进入 logger 中间件
    var start = new Date;
    yield next;
    // (4) 再次进入 logger 中间件,记录2次通过此中间件「穿越」的时间
    var ms = new Date - start;
    console.log('%s %s - %s', this.method, this.url, ms);
    });

    // response
    app.use(function *(){
    // (3) 进入 response 中间件,没有捕获到下一个符合条件的中间件,传递到 upstream
    this.body = 'Hello World';
    });

    app.listen(3000);

    this
        request
            header
            headers
            url
            accepts
        response
            header
            headers
            status
        cookies
            set('name', 'tobi', {signed: true})
                signed
                expires
                path
                domain
                secure
                httpOnly
            get
        type
        length
        path
        method
        state
        throw
        assert
    app
        use
        listen
        callback
        keys
        context
            db
中间件
    koa-router
    trie-router
    route
    basic-auth
    etag
    compose
    static
    static-cache
    session
    compress
    csrf
    logger
    mount
    send
    error

实时 #

sockjs
        # node websock
postal
        # nodejs 在内存上构建的发布订阅框架
pusher
        # 发布订阅模式socketio框架
juggernaut
        # 基于socketio
datachannel.io
        # 基于socket.io和html5 webRTC的实时聊天室框架
faye-websocket-node
        # 扩展faye项目开发的websocket的一个实现, 非常简单,而且不依赖其他库
websocket-node
        # 一个简单的websocket库,支持draft-10及之前的各种版本, 支持同样是node的c/s交互模式
ejabberd
        # 基于erlang/OTP 的xmpp im 开源框架
singalR
        # .net sock服务
nsq
        # go
openfire
        # java, 性能较差, 最多单机10w并发
webrtc
        # c++实现的web视频聊天

socket.io #

# 介绍
    socket.io: 基于任何浏览器, mobile设备的"webSocket"
# 安装
        npm install socket.io
# 使用
        var socketIo = require('socket.io');
        socketIo.listen(app).on('connection', function (socket) {                # require('socket.io')(app);
                                                                        ## var io = require('socket.io')(80);
        socket.emit('news', { hello: 'world' });
        socket.on('my other event', function (data) {
                console.log(data);
        });
        });
# api
    server
            io.on('connection', function(socket){});
            io.on('disconnect', function(){});
            socket.on('message', function(msg){});
    client-js
            socket = io.connect(url);
            socket.on('', function(json){});
            socket.send(json);
    io
            on('connection', function(socket){});
                    # disconnect
    socket
            on('disconnect', function(){ });
            socket.on('say to someone', function(id, msg){
                    socket.broadcast.to(id).emit('my message', msg);
            });
                    # Socket#id为内部指定的
    遍历用户
            var roster = io.sockets.clients('chatroom');
            roster.forEach(function(client){
                    console.log('Username: ' + client.nickname);
            });                        // 1.0之前版本可用
# 方案
    namespace
            server
                    var nsp = io.of('/my-namespace');
                    Onsp.emit('hi', 'everyone!');                # ns广播
            client
                    var socket = io('/my-namespace');
    room
            server
                    socket.join('some room');
                    io.to('some room').emit('some event'):        # room广播
                    socket.leave('some room');
# 子模块
    socket.io-redis
        介绍
                用于从外部发消息,与socket.io-emitter一起使用
        使用
                var io = require('socket.io')(3000);
                var redis = require('socket.io-redis');
                io.adapter(redis({ host: 'localhost', port: 6379 }));
    socket.io-emitter
        介绍
                用于从外部发消息,与socket.io-redis一起使用
        使用
                var io = require('socket.io-emitter')();
                io.emit('time', new Date);
    socket.io-client
        介绍
                用于创建客户端来连接socket.io
        使用
                var iocl = require('socket.io-client');
                var socket = iocl.connect('127.0.0.1:5555');
                socket.on('connect', function(){

                });

展示 #

titles
    # java apache的标签库

spring mvc #

struts2 #

# 基础
    介绍
        struts1和WebWork的发展
        引入值栈的概念     # 一次请求的参数和处理数据放在一个map结构中
    原理
        基于拦截器, 解耦servlet, 再提供自己的拦截器(interceptor)操作数据, 反射调用业务类
        FilterDispatcher通过配置文件来映射设置请求地址与处理类
            ActionMapper判断请求是否struts处理
            ActionProxy扩展实现方式(如web service)
            ConfigurationManager对应struts.xml配置文件
            ActionInvocation执行Action与拦截器
            Action处理请求,封装数据
                # Action是非单例的,效率低
    过滤器与拦截器
        过滤器基于回调,拦截器基于反射
        过滤器依赖servlet, 拦截器在struts中处理action

# 思想
    Action类中的无侵入设计(新技术中不出现旧技术):map代替了作用域
        ActionContext actionContext = actionContext.getContext()
        actionContext.getApplication()
        actionContext.getSession()

        好处
            map是java中的api,不出现旧技术
            测试方便( servlet不能测试,只能发布测试)
                # 注意:Action类中用到作用域map的方法也不能测试


# 结构
    apps: 例子程序
    docs:帮助文件
    lib:程序包
    src:源码
# 使用
    要求
        jdk5
        jsp2
        servlet api2.4

    导入核心的8个包
        struts2-core-2.3.1.1.jar        # struts的过滤器
        xwork-core-2.3.1.1.jar                # 验证工具
        freemarker-2.3.18.jar                # 标签
        javassist-3.11.0.GA.jar                # 动态代理
        commons-fileupload-1.2.2.jar
        commons-io-2.0.1.jar                # 文件处理
        commons-lang-2.5.jar                # 基础包
        ognl-3.0.3.jar                                # 表达式语言
    web.xml文件中配置过滤器
        <filter>
            <filter-name>struts</filter-name>
            <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>struts</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    写jsp页面,get或post路径为struts2的名称空间、扩展名,被配置的struts2过滤器处理
    写Action类(继承ActionSupport类)
    配置src/struts.xml文件与src/struts.properties文件,映射类、方法等到请求路径,映射返回字符串到任何方式


# 核心包:8个
    struts2-core-2.3.1.1.jar        # struts的过滤器
    xwork-core-2.3.1.1.jar                # 验证工具
    freemarker-2.3.18.jar                # 标签
    javassist-3.11.0.GA.jar                # 动态代理
    commons-fileupload-1.2.2.jar
    commons-io-2.0.1.jar                # 文件处理
    commons-lang-2.5.jar                # 基础包
    ognl-3.0.3.jar                                # 表达式语言

# 配置
    struts2以包的形式管理action 包名必须唯一,包里的每个action唯一
    使用步骤
        导入lib包
        写jsp
        编写Action方法
        web.xml中配置
            <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
            <url-pattern>/*
        ../xx_struts.xml中配置请求响应
        src/struts.xml 中引入配置文件
            <include file="cn/itcast/javaee/cal/cal_struts.xml"/>

    配置文件(配置包)路径
        重要路径:4个
            1./struts-default.xml[框架]
                # 是框架自带的abstract包(包括上传,下载,验证等),继承它以后可以用其中的功能
            2./org/apache/struts2/default.properties[框架]
            3.src/struts.xml # 必有
            4.src/struts.properties # 可选
        验证返回消息的配置文件
            struts2-core-2.3.1.1.jar包中的
                /org/apache/struts2/struts-messages.properties文件

    xml 中配置的简化
        *
            o-> 只能在name 中写*_* 等
            o-> 引用第一个* 用{1}        引用第二个用{2} 以此类推


    类路径
        com.opensymphony.xwork2.ActionSupport  默认关联到的类

    处理请求的扩展名配置
        # 扩展名配置只有一个会生效
        1./org/apache/struts2/default.properties
                struts.action.extension=action,,
                # 框架中初始的默认扩展名,最后的','代表了无扩展名
        2.src/struts.xml中
                <constant name="struts.action.extension" value="do,,">
                        # 必需配置
        3.src/struts.properties中
                        struts.action.extension=xx,yy
                        # 选择配置,优先级高

    默认配置
        struts2内置了请求字符串与基本类型的相互转换,不用手工转换

        /org/apache/struts2/default.properties文件中
                struts.i18n.encoding=UTF-8        # post方式请求响应的编码方式
                                                                        ## get方式的没有默认值,需要自己转码
                struts.action.extension=action,,  # 框架中初始的默认扩展名,最后的','代表了无扩展名

        每个<package>标签中配置
        <interceptor-ref name="defaultStack"></interceptor-ref> 为默认的拦截器

    src/struts.xml配置文件

    src/struts.properties配置文件

# 原理流程
    请求/qq.action -> StrutsPreparedAndExecuteFilter(核心过滤器)-> 匹配扩展名 -> 匹配命名空间
        #( 全限定名:org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.class)
            -> src/struts.xml                -> name
                class
                method
            -> name
                type
                内容
            -> 响应
            -> 拦截器 -> ConfigAction类

        # 1.部署时读取src/struts.xml和src/struts.properties文件,形成JavaBean对象
                # 两个文件同时存在时src/struts.properties文件为准
        ## 2.请求/*路径时,StrutsPreparedAndExecuteFilter过滤
        ## 3.获取JavaBean中的actionName ,actionClass, actionMethod, 执行方法
        ## 4.执行的返回值与resultName, resultType, resultContent进行比较
        ## 5.按resultType类型返回resultContent(路径和内容)

# 缺点
    8个jar包,慢,servlet 快
    配置繁琐
# 编码
    struts2默认编码方式:utf-8

    返回的图片相对路径中有中文时设置tomcat
        tomcat/conf/server.xml
            <Connector port="8080" .. URIEncoding="utf-8"/>

        这时点击下载的请求路径中有中文时在以post方式提交 ,struts自动转码。若以get方式提交,需要在Action类的相应的get方法中转换url编码(iso8859-1)到u8

        原理
                改了tomcat的内部编码以后,struts中的编码是u8,放在session 中,jsp支持u8,解释后发送的html中的编码没问题,查看没问题。
                下载post发送请求,浏览器请求的是url编码的u8,struts中也是u8执行下载

                如果不改编码,struts 中是u8,如果以List方式放入session的话,session存储的是u8
                如果直接放入数据的话,session中存储的是8859-1,jsp取出数据需要转码为u8并设置自己的编码是u8,再发送给浏览器。
                浏览器这时获取图片正常,post方式提交的是u8,经过tomcat转换为8859-1,struts中自动转换编码到u8
                如果是以get方式提交请求,get中的中文在浏览器时进行url编码到8859-1,经过tomcat,再到struts,struts不对get方式的请自动进行转码
                向action类中注入参数时是8859-1编码,需要手动在action类中的属性的get方法中进行8859-1到u8的转码操作
# 内置对象
    struts中的6个内置对象
        # request请求进入struts中时创建,request请求结束时销毁。
        requestMap
        sessionMap
        applicationMap
        parameters
        attr                        # page -> request -> session -> application 的顺序查找
        valueStack                # 定义实例变量,直接放入valueStack的 list(栈) 中,map(值)很少向内存储数据
            # 定义的实例变量必须提供相应的get方法,否则ognl标签中取其数据时没有方法调用,就得不到它的值
            # list 中的值优先访问 ,但是map 中的值起决定作用
            # map中存放着一个大map,其中注入了所有页面的请求信息
                # requestMap sessionMap applicationMap 并不是真正的域对象,但最后通过拦截器放入到域对象中

# 异常处理
    配置src/strut.xml 文件
        <global-results> 全局结果(用来跳转全局异常等)
        <global-exception-mappings> 全局异常
        <exception-mapping result="nullJsp"        exception="java.lang.NullPointerException" />
            # <action>标签中的局部异常
            ## <action>捕获标签中的实例运行抛出的异常,然后改为 返回执行结果为"nullJsp"的字符串交给本<action>标签中相应的<result>标签来处理


    处理机制
        o-> 多个异常时走子异常,父异常被忽略
        o-> 先处理小范围异常,大范围忽略
        o->  如果异常没有处理,抛出到web服务器处理,web.xml的<error-page><error-code><location>
    全局异常
        xml文件中
            <global-results>
                <result name="error">
                    /error.jsp
                </result>
            </global-results>
            <global-exception-mappings>
                <exception-mapping result="error" exception="java.lang.Exception"/>
            </global-exception-mappings>
        error.jsp页面中
            <%@ taglib prefix="s" uri="/struts-tags" %>
            异常信息:<s:property value="exception.message"/><br/>
            详细信息:<s:property value="exceptionStack"/><br/>


# 转递方式
    chain                        # action类之间转发
    dispatcher                # 转发到jsp
    freemarker
    httpheader
    redirect                # 重定向到页面
    redirectAction        # action 类之间重定向
    stream                        # 返回 InputStream流
    velocity
    xslt
    plainText
# Action类
    注意
        1.所有Action类都要继承ActionSupport类,否则execute方法返回的字符串不会回到struts拦截器再根据xml文件的配置进行转发
        2.action类是非单例的。        # 所有多实例的对象全部是因为有私有属性,否则全部应该是单例的
        3.action类放在栈的顶端,用于注入数据

    传统方式得到request,response,servletContext,pageContext
        ServletActionContext.getPageContext()
        HttpServletRequest request = ServletActionContext.getRequest()
        ServletActionContext.getResponse()
        ServletActionContext.getServletContext();

    优势
        实现与servlet的解耦

    验证
        验证分类
                前台验证:javascript等
                后台验证:服务器
        struts2验证
                    后台验证
            1.代码式验证
            2.声明式验证:xml文件

    ActionContext类
        调用方法
        ActionContext actionContext = ActionContext.getContext();
        得到内置对象        # 这几种得到作用域的方法均可以得到作用域中原有的值,也可以放入值
        request
                actionContext.put("","");
        application
                Map<String,Object> applicationMap = actionContext.getApplication();
        session
                Map<String,Object> sessionMap = actionContext.getSession();
                        # 或 actionContext.get("session")得到,因为actionContext中存储着大map
        parameters
                Map<String,Object> parametersMap = actionContext.getParameters();
        valueStack
                ValueStack valueStack = actionContext.getValueStack()
                valueStack.getRoot()                        # 得到当前值栈的顺序

    参数
        1.action类中可以直接创建属性与其get方法得到客户端get方法或post表单请求的参数(由struts2自动注入)
        2.action类中可以创建 JavaBean的属性来接收struts注入的参数,这时用户请求的参数名字要写成JavaBean名.JavaBean中的属性名(这样struts2会自动调用JavaBean的set方法来注入其中相应的参数 )
## BaseAction
    作用
        权限管理
        存放常驻内存数据
        抽取常用的方法
# web.xml配置
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class> org.apache.struts2.dispatcher.FilterDispatcher </filter-class>
        <init-param>
            <param-name>struts.action.extension</param-name>
            <param-value>do</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>*.json</url-pattern>
    </filter-mapping>
        # 设置全局过滤器,并且修改过滤扩展名
# default.properties
    src/struts.properties配置文件
        struts.custom.i18n.resources=struts    # 使自己的普通配置生效。如:/org/apache/struts2/struts-messages.properties文件的
            ## struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}  属性,"{1}" "{2}" "{3}"是显示消息的占位符
            ## struts.action.extension=action,,可以不配置
            # 由于只加载properties文件,所以省略.properties
            ## =后面的是相对于src目录的文件
# ognl标签
    注意
        # jquery中不能定位ognl标签,而要用标签自己生成的id定位(看源码得到)
    使用:
        <%@ taglib uri="/struts-tags" prefix="s" %>
        tld映射文件路径
            struts2-core-2.3.1.1.jar包中
            /META-INF/struts-tags.tld

    '#'出现的地方
        o-> 除ValueStack 之外的所有struts内置对象的取值前面都要加
        o-> 取JavaBean中的属性时要加 '#',如"#user.username",ValueStack中也不例外
        o-> 构造Map对象,Map:#{'male':'[男]','female':'[女]'},构造radio和select标签,如
                        # <s:radio list="#{'male':'aa','bb':'cc'}" name="gender2" />
        o-> 迭代数组或list集合
            集合的投影:userList.{username}
            集合的过滤:userList.{?#this.age>22}

    主题与模板
        主题:为多个模板提供风格
            struts2-core-2.3.1.1.jar包中
                template中的四个主题
                    archive                # 其中是.vm文件,其它是.ftl文件。vm与ftl是两种视图技术
                        ajax        # 除此之外其它都不支持ajax
                        simple
                        xhtml
                    xhtml                # 默认主题,default.properties配置文件中定义
                    css_xhtml
                    simple
            修改主题
                1.struts.properties 中修改
                    struts.ui.theme=simple          # 针对当前webapp
                2.<s:form theme="xhtml">            # 只针对当前表单
                3.<s:textfield name="username" theme="simple">  # 修改某个标签的属性
        模板:为标签提供样式
                做模板的技术freemarker

    ognl标签的优点:自动排版、验证数据回显、国际化

    所有标签:
        逻辑标签
            对 Map 集合的迭代:
                <s:iterator value="#session.fileMap" var="entry" status="stat">
                    <s:property value="#entry.key"/>
                <s:if test="#stat.count%4==0"></s:if>
                </s:iterator>
            对 List 集合的迭代  List<User> userList
                普通迭代
                    <s:iterator var="user" value="userList">      # 投影语法List<user>中的所有username
                    <s:property value="#user.username"/>
                        投影语法
                    <s:iterator var="username" value="userList.{username}">
                    <s:property/>                        # 这里不用写属性value="username"就可以对page域中的username进行显示
                过滤语法
                    <s:iterator var="user" value="userList.{?#this.age>9}">
                        # this代表当前被迭代的元素 ?#是所有 ^#是第一个 $#是最后一个  ?#...[0]按标记取
                    <s:property value="#user.username" />
        显示标签(UI标签)
            普通字符串中使用ognl
                jsp中用%{}      xml中用${}
                例如
                jsp中:<s:textfield label="%{#attr.testValueStack}"/>
                xml中:<param name="min">4000</param>
                                            <message>${min}</message>
            普通信息
                <s:text name=""/>
            输出值
                迭代器中
                        <s:property/>        # 直接输出被迭代的内容(简单)
                        <s:property value="aa"/>
                        <s:property value="#aa"/>
                普通
                        <s:property value="username"/>      # 输出标签,得到valueStack中属性
                        <s:property value="#request.name"/>                # 得到request域对象中的值
                                # request #session #application #parameters #attr
                                # '#attr'优先级:page,request,valueStack,session,application
            显示验证拦截器的验证信息集合中的数据:
                <s:fielderror/>                                                        # 显示所有错误信息
                <s:fielderror fieldName=""/>                        # 显示验证返回的错误信息
            单选
                <s:radio list="#{'male':'男','female':'女'}" name="gender2" value='男'>
                                # 自动加class id <label for="gender2male">等
                                # list键值对中male是实际值,男是显示值
                                # name是<input radio >的name属性
                                # value中是选中的项
            多选
                <s:select multiple="true" list="#{'bj':'北京','sh':'上海','gz':'广州'}" name="select1" value="{'sh','bj'}"/>
            表单                        # 在ognl的标签中, struts的验证消息自动回显,不用加<s:fielderror/>标签
                <s:form action="">                # 默认中加上了 method="post" action中加上了当前网站了contextPath路径
                        <s:textfield label="用户名" name="username" />
                        <s:password label="密码" name="password" />
                        <s:submit value="登录" />
            国际化                # 国际化一般放在整个网站的最后写
                                ## 伪国际化:将不同语言的页面放在不同文件夹中分别访问
                        # 国际化是通过i18n拦截器实现的
                1.创建国际化信息文件
                        message_zh_CH.properties      # 基名_语言名_国家名.properties
                                username=xxx
                                password=xxxx
                                submit=xx
                        message_en_US.properties
                        ..
                        message.properties                # 默认的显示语言
                                # 找伊拉克没有的话找本地区语言,本地语言没有的话找其它(默认的或美国等)
                2.struts.properties中引入国际化配置的属性文件
                        struts.custom,i18n.resources=struts2/tag/i18n/message        # 从src文件夹路径开始,只写基名
                3.验证消息国际化
                        message.properties文件中配置属性validationRequiredUsername=用户名错误
                        validation.xml文件中
                        <message key="validationRequiredUsername"></message>
                4.jsp文件中用key属性代替 label属性(或其它在页面上显示信息的属性),key中写国际化信息文件中的key
                        <s:form action="taglogin">
                                <s:textfield key="username" name="username" />
                                <s:password key="password" name="password" />
                                <s:submit key="submit"/>
                        </s:form>
                5.普通信息的国际化
                        message.properties中配置属性 normalMessage:普通信息
                        jsp中<s:text name="normalMessage"/>
                6.测试
                        intername选项 -- 语言 改地区访问

    xml文件中的ognl标签
            o-> ${aa}
                    1.调用转到该标签类的getAa()方法得到aa的值替换${aa}
                    2.本标签中name="aa"的标签的文本节点的内容
            o-> {1}{2}{3}..{n}
                    匹配本标签中name="*a*" 中的第n个‘*’,用于通配传递过来的参数的一部分的值
# ognl表达式
    ognl 开源,java写的免费标签,是struts2特有的

    xml文件中
        ${Xxx}                取值栈中栈中的东西,如action类中的属性
        ${#Xxx}                取值栈中值的东西,如request,session域中的数据(其实就是老师说的内置对象【valueStack就是值栈】)

    jsp文件中
        <s:iterator value="#session.fileMap" var="entry" status="stat">
            <s:property value="#entry.key"/>
            <s:if test="#stat.count%4==0"></s:if>
        </s:iterator>
# strut.xml配置
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE struts PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
            "http://struts.apache.org/dtds/struts-2.0.dtd">

    <struts>
        <constant name="" value=""></constant>
        <include file=""></include>
        <package name="">
                <interceptors>
                        <interceptor name="" class=""></interceptor>
                        <interceptor-stack name="">
                                <interceptor-ref name=""></interceptor-ref>
                        </interceptor-stack>
                </interceptors>
                <default-interceptor-ref name=""></default-interceptor-ref>
                <global-results>
                        <result name=""></result>
                </global-results>
                <global-exception-mappings>
                        <exception-mapping result="" exception=""/>
                </global-exception-mappings>
                <action name="">
                        <param name=""></param>
                        <result></result>
                        <result name="input"></result>
                        <exception-mapping result="" exception=""/>
                        <interceptor-ref name=""></interceptor-ref>
                </action>
        </package>
    </struts>

    设置
        <constant name="struts.devMode" value="true"/>                # 开启debug模式
                                                                # debug模式,不用重启调试(添加新的方法要重启,方法中改代码不用重启)
        <constant name="struts.i18n.encoding" value="utf-8"/>
                                                                # 配置struts的编码
        <constant name="struts.configuration.xml.reload" value="true"/>
                                                                # 配置本属性,可以使得改动struts配置文件不用重启应用服务器
        <constant name="struts.multipart.saveDir" value="/upload"/>
                                                                # 配置上传存储路径
        <constant name="struts.action.extension" value="action,do" />
                                                                    # 配置过滤路径
    详细解释
        o-> 存放路径src/
        o-> 可以在struts-2.3.15.1的src\apps\blank\src\main\resources\struts.xml中参考配置文件
        o-> <include file="struts2/cal/cal_struts.xml"/>标签包含其它路径的xml配置文件
                        # 被include的文件不能再include其它文件
        o-> <constant name="struts.action.extension" value="do,,">
                默认值
                        default.properties中配置了默扩展名:struts.action.extension=action,,
                # 配置匹配到框架处理的扩展名,空逗号代表匹配没有扩展名
        o-> <package name="xxPackage" extends="struts-default" namespace="/xx/">
                默认值
                        namespace="/"
                        extends="struts-default"        # 不可省略
                # name是包的唯一标识,不可以写路径
                ## namespace 访问路径如/xx/a.do会匹配到该包执行其中的映射,按照域命名空间链的方式匹配,如:
                                                        /xx/yy/a.do也会匹配到该包,但是它优先匹配到/xx/yy的命名空间
                                                        /a.do 不会匹配到该包
                        注意:匹配/sys/*的名称空间是/sys 而非 /sys/
                ## struts的包有抽象包,普通包两种,通过继承可以加入包内容,相当于复制、粘贴
                ## 继承的包是struts-default,其路径是/struts-default.xml
                ## ,它定义了核心的bean和拦截器
        o-> <interceptors>
                        <interceptor name="" class=""/>
                        <interceptor-stack name="">
                                <interceptor-ref name="/">
                                # 定义拦截器、定义拦截器栈(加入拦截器)
                                ## 拦截器栈中可以加栈
        o-> <default-interceptor-ref name=""> 默认拦截器(可以用于验证用户登录)
        o-> <global-results> 全局结果(用来跳转全局异常等)
        o-> <global-exception-mappings> 全局异常
        o-> <action name="" class="" method="">
                默认值
                        class="com.opensymphony.xwork2.ActionSupport"
                        method="execute"
                # name="aa"时 .../aa.do的请求匹配到该方法执行
                ## class 是类字节码路径,method是其中的方法名
        o-> <param name="aaa">bbb</param>
                调用 <action>标签中对象的实例的方法:setAaa("bbb");
        o-> <result name="" type="">/ok.jsp
                默认值
                        name="success"
                        type="dispatcher"
                # name="success"时,映射的method返回"success"时进入该result处理
                ## type是返回方式 ,如dispatcher redirect等
                        type的返回类型
                                dispatcher : 转发到jsp页面
                                redirect : 重定向到 jsp html 等页面
                                chain : Action 类之间的转发
                                redirectAction : Action 类之间的重定向
                                stream : 以 inputStream 的数据类型返回
                                        stream的参数                        # 可以从struts-default.xml文件中对应的stream参数对应的类的源码中查看其中的set方法找到要写参数的名称
                                                <param name="contentType">image/pjpeg</param>                # 下载文件的类型                  另外如text/html; charset=utf-8返回给ajax异步数据
                                                <param name="bufferSize">2048</param>                # 缓冲byte[]的大小,单位字节
                                                <param name="contentDisposition">attachment;filename=${uuidFileName}</param>                # 设置下载响应头,只的下载时才设置。${uuidFileName}是一个OGNL表达式
                                                <param name="inputName">imageStream</param>        # 框架调用传递给result标签结果字符串的对象中的getImageStream()方法,来获取InputStream流对象
                                                # 返回stream类型不指定返回的路径
                ## 标签间的内容:/ok.jsp 是响应的路径
        o-> <result name="input" type="">/ok.jsp
                type中的参数                        # 可以从struts-default.xml配置文件中查到
                        dispatcher        # 转发
                        redirect        # 重定向
                        chain                # Action类之间转发,需要加参数,参数的名字
                                                ## :struts-default.xml文件中找到"chain"对应的类,按快捷键ctrl + shift + T 关联类的源码文件,查找set方法改名即可
                                <param name="actionName">to</param>
                                        # action标签的 name属性值
                                <param name="namespace">/</param>
                                        # action的名称空间
                        redirectAction                # Action类之间重定向

                # 各种拦截器不通过时默认的返回input,同时向request作用域中加入了相关错误信息供struts2的jsp标签进行显示
                ## 处理 返回值是input的返回信息跳转,就是处理拦截器拦截后的信息跳转
        o-> <exception-mapping result="nullJsp"        exception="java.lang.NullPointerException" />
                # <action>标签中的局部异常
                ## <action>捕获标签中的实例运行抛出的异常,然后改为 返回执行结果为"nullJsp"的字符串交给本<action>标签中相应的<result>标签来处理
        o-> <interceptor-ref name="loginInterceptor"/>
                默认值
                        name="defaultStack"
                # 指定在本<action>标签中使用的拦截器或拦截器栈
                ## 当指定了拦截器或拦截器栈以后,默认的defaultStack将会没有,此时defaultStack中的18个拦截器将不再执行

    使用:OGNL对象图导航语言对标签中的路径进行动态设置

# 验证
    struts2验证
        1.代码式: validate(),validateXxx()方法
                        # 单个验证与全部验证都存在时先单个验证,再全部验证,验证信息都加入验证信息集合
        2.声明式: Action类名-validation.xml
                                Action类名-<action标签的name属性>-validation.xml
                            # 单个验证与全部验证都存在时先全部验证,再单个验证,验证信息都加入验证信息集合
                    # 先声明验证,后代码验证
    参数驱动
        1.属性驱动: action中用属性收集表单参数
        2.模型驱动: javaBean收集参数

    代码式(属性驱动):
        步骤
        1.需要验证的Action类  继承 ActionSupport 类
                        # ActionSupport 类 实现了Validateable接口,该接口是验证接口

        2.写验证方法
                1> public void validate()
                                # 方法重写(通用验证方法,本类中的所有其它方法执行前都执行)

                2> public void validateXxxMethod()
                                # 或者自定义专用验证方法 xxxMethod为要验证的方法名,首字母要大写

                        # 注意,通用、专用验证方法同时存在时,先执行专用验证方法,再执行通用验证方法
                        ## ,但是通用验证方法的错误消息无法加入到返回的错误集合中

                3> this.addFieldError("password","密码必填");

                        # 验证方法中添加错误信息到错误信息集合
                        ## addFieldError("","")是从ActionSupport父类中继承的方法

        3.jsp文件中通过验证标签:
                        <%@ taglib uri="/struts-tags" prefix="s"%>
                        <s:fielderror/>                # 显示所有错误信息
                        <s:fielderror fieldName="password"/>
                显示验证出错信息

        4.xml配置
            <!-- 验证错误信息处理 -->
                <result name="input" type="dispatcher">
                        /error.jsp
                </result>
                        # 写在需要验证的方法对应的标签中,验证错误时验证方法会优先返回"input"字符串


    声明式(属性驱动):
        1.验证Action类继承ActionSupport
        2.验证Action类目录下配置文件
            Action类名-validation.xml
            Action类名-<action标签的name属性>-validation.xml
                # 放入此名字的配置文件就相当于加了验证,不需要做其它事情
                ## ,相当于分别向Actioin类中加入了validate()validateXxx()方法进行了相应验证
                文件内容
                <?xml version="1.0" encoding="UTF-8"?>
                    <!DOCTYPE validators PUBLIC
                    "-//Apache Struts//XWork Validator 1.0.3//EN"
                    "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
                    <validators>
                            <field name="username">                # 要验证的属性
                                    <field-validator type="requiredstring">
                                            <message>用户名必填</message>
                                    </field-validator>
                            </field>
                            <field-validator type="regex">
                                    <param name="expression">^[\u3447-\uFA29]+$</param>
                                    <message>UserAction2-validation==>必须写中文</message>
                            </field-validator>
                    </validators>

                            # xml文件的头在 xwork-core-2.3.1.1.jar包的
                                    xwork-validator-1.0.3.dtd中复制
                            ## 关联约束在
                                    \struts-2.3.15.1\src\xwork-core\src\main\resources\xwork-validator-1.0.3.dtd文件
                            ## <field-validator type="">的约束类型在xwork-core-2.3.1.1.jar包的
                                            /com/opensymphony/xwork2/validator/validators/default.xml文件中
                                                    # 16个规则
                                                    ## type="regex"相当于调用了default.xml文件中配置的
                                                        ## RegexFieldValidator类的 setExpression方法
        3.jsp文件中通过验证标签(同上)
        4.xml配置(同上)
            # 出错信息
                1.验证文件名写错,无提示,不验证
                2.<field-validator type="">写错,有明显提示
                2.<field name="salaryy">写错,获取的salaryy为空。

    声明式(模型驱动)
            1.创建bean对象,bean对象中封装属性
            2.验证Action类继承ActionSupport类,声明bean对象实例
            3.action类同目录 中  :Action类名-<action标签的name属性>-validation.xml
                            # <field-validator type="visitor">
                    # bean类同目录中:bean类名-validation.xml配置验证文件
            4.jsp文件请求参数改为:action类中bean对象名.bean对象封装的属性名。用<s:fielderror/>标签得到返回的错误信息
            5.xml配置(同上)

    原理
    StrutsPreparedAndExecuteFilter
        1.注入参数
                setUsername()
            setPassword()
        2.验证方法:validate()或validateXxx()
                        验证配置文件中验证:Action类名-validation.xml
        3.转发:根据验证成功或失败返回消息
                        验证集合无错误消息成功Action --> execute或同签名的方法
                        验证集合有错误消息失败<result name = "input" type="dispatcher"
                                            register.jsp/login.jsp
# 过滤器
    StrutsPrepareAndExecuteFilter
        中查看Dispathcer类,从中找到配置struts-default.xml,struts-plugin.xml,struts.xml值的属性DEFAULT_CONFIGURATION_PATHS
        查找引用该属性的方法为init_TraditionalXmlConfigurations
        查看引用该方法的方法为init
        回头看StrutsPrepareAndExecuteFilter中初始化dispatcher对象的方法initDispatcher
                其中调用了dispatcher.init();方法来配置dispatcher
        由此可以知道struts在启动时加载了struts-default.xml,struts-plugin.xml,struts.xml配置文件
# 拦截器
    struts-core-2.3.1.1.jar包中的
        struts-default.xml文件中
                定义了32个interceptor(拦截器)
                        i18n    # 国际化
            token  # 表单重复提交
            validation  # 验证
            params  # 参数拦截器,向Action类中注入参数
            cookie
        interceptor-tack    # 拦截栈
                # 拦截栈中的拦截器的先后顺序有影响
                basicStack
            defaultStack    # 每个http请求都会经过该拦截栈
                            ## 其中的18个拦截器, <default-interceptor-ref>中定义
    原理
            拦截器仿照过滤器建立,内部实现原理是完全相同的
    执行流程
            拦截器构构造函数 -> action构造函数 -> 拦截器1 in -> 拦截器2 in -> demo -> 拦截器2 out -> 拦截器1 out
        exception拦截器最先进,最后出
    自定义拦截器
        1.定义Action类,继承Interceptor接口,重写生命周期方法
            public LoginInterceptor() {
            }
            public void destroy() {
            }
            public void init() {
            }
            public String intercept(ActionInvocation invocation)  {
            }
        2.配置struts.xml文件
            1> 定义拦截器、拦截器栈
                <interceptors>
                    <interceptor name="loginInterceptor" class="interceptor.LoginInterceptor"/>
                    <interceptor name="roleInterceptor" class="interceptor.RoleInterceptor"/>
                    <interceptor-stack name="crmStack">
                        <interceptor-ref name="loginInterceptor"></interceptor-ref>
                        <interceptor-ref name="roleInterceptor"></interceptor-ref>
                    </interceptor-stack>
                </interceptors>
            2> <action>标签中声明用到的拦截器或拦截器栈
                    <interceptor-ref name="loginInterceptor" />                # 此时默认的defaultStack拦截器栈会被替代掉
    自定义方法过滤拦截器
        # MethodFilterInterceptor继承AbstractInterceptor继承Interceptor,前两个是struts自己实现的自己的包装类
        ## 原理:自己实现intercept方法,实现对方法名的过滤。如果符合通过条件,则执行自己的doIntercept方法。所以要求用户重写doIntercept方法实现业务逻辑
        <interceptor name="aloginInterceptor" class="cn.it.shop.interceptor.AloginInterceptor">
            <param name="excludeMethods">*$</param>                # 除了*$匹配的方法都执行此拦截器
                    ## includeMethods为包含匹配的方法执行拦截器
        </interceptor>
    生命周期
        部署时初始化,每次符合<action>的请求时,执行拦截器
    拦截器Action 类
        o-> 继承Interceptor 接口
        o-> 重写生命周期方法
            String intercept(ActionInvocation invocation)方法中调用
                invocation.invoke() 放行
                invocation.getAction()得到当前的Action类
                invocation.getStack()得到值栈中的栈
                    # invocation用于调试18个拦截器
    具体拦截器
        struts-default.xml 文件中定义了32种拦截器
                alias
        autowiring
        chain
        conversionError
        cookie
        clearSession
        createSession
        debugging
        execAndWait
        exception
        fileUpload                                # 只用来验证已经注入的文件是否合格,合格则通过,不合格则不执行action类中对应请求的方法
        i18n
        logger
        modelDriven                                # 用于检查action类是否实现ModelDriven<T>接口,然后调用getModel()方法注入得到的对象到栈的项端。
        scopedModelDriven
        params                                        # 注入参数用,包括注入文件(级联注入文件的ContentType与FileName)
        actionMappingParams
        prepare
        staticParams
        scope
        servletConfig                                # 向自定义的实现RequestAware等接口的Action类(一般是BaseAction类)中注入request等相应的map对象
        timer
        token                                                # 防止重复提交
        tokenSession
        validation                                # 验证
        workflow
        store
        checkbox
        profiling
        roles
        annotationWorkflow
        multiselect
    数据传递
        o-> 拦截器不会向其它拦截器中注入参数,所以自定义拦截器中了参数要从request中获取
        o-> 如果想 显式的引用了自己的拦截栈,默认的拦截栈就不引用了,要自己引用,其中的注入参数拦截器向action类中注入参数
    技巧
        <interceptor-stack name="defaultStack">    # 对defaultStack进行替换,在它前面添加自定义的拦截器
        <interceptor-ref name="aloginInterceptor"/>
        <interceptor-ref name="defaultStack"/>
    拦截器中的ActionInvocation对象
        可以得到ActionContext

# 文件处理
## 上传
    struts2文件上传步骤
        1.编写jsp文件
                1> post方式提交
                2> <input type="file" name="file1"/> 要添加name属性
                3> post表单上传的编码方式是enctype="multipart/formdata"
        2.创建Action类,不必继承任何类(但是如果不继承ActionSupport类的话,拦截器将不会返回提示消息)
                1> 定义参数        # 如果不接收上传文件名字符串数组而从文件对象中获取文件名的话,得到的文件名将会是乱码
                        private File[] image;                                                # 字段名
                        private String[] imageContentType;                        # 文件类型
                        private String[] imageFileName;                                # 文件名
                        private String uploadPath;
                                        # 前三个参数可以不是数组,在 struts-default.xml配置文件fileUpload拦截器对应的源码中可以找到定义规则:
                                                <li>[File Name] : File - the actual File</li>
                                                <p/> <li>[FileName]ContentType : String - the content type of the file</li>
                                                <p/><li>[File Name]FileName : String - the actual name of the file uploaded(not the HTML name)</li>
                                        # uploadPath是我们自定义的配置文件中注入过来的文件存储位置

                2> 写execute方法保存文件到路径,返回成功消息
        3.Action类的配置文件,include到src/struts.xml文件中
                        1> <action>标签中配置name="input"的标签<result>来返回出错消息
                        2> <action>标签中用param标签注入文件存储路径:uploadPath 底层执行setUploadPath()方法
                        3> <action>标签中通过<interceptor-ref name="fileUpload">标签对上传文件进行参数上的限定
                                1> <param name="maximumSize"> 单个文件的最大尺寸(字节)
                                2> <param name="allowedExtensions"> 文件扩展名
                                3> <param name="allowedTypes"> 文件实际类型,如image/jpeg,可从tomcat配置文件web.xml中查找
        4.配置返回消息的信息
                :src/struts.properties文件中
                        struts.custom.i18n.resources=struts                # 解锁自/org/apache/struts2/default.properties总配置文件
                                        # 加载自己,=后面是参照src/目录的相对路径 ,省略掉.properties扩展名
                        struts.multipart.maxSize=2097152                #  解锁自/org/apache/struts2/default.properties总配置文件
                                        # 设置上传文件总量的大小
                        struts.messages.error.file.too.large=\u6587\u4EF6\u592A\u5927\: {0} "{1}" "{2}" {3}
                        struts.messages.error.content.type.not.allowed=\u6587\u4EF6\u7C7B\u578B\u4E0D\u6B63\u786E\: {0} "{1}" "{2}" {3}
                        struts.messages.error.file.extension.not.allowed=\u6269\u5C55\u540D\u4E0D\u6B63\u786E\: {0} "{1}" "{2}" {3}
                                        # 覆盖/org/apache/struts2/default.properties总配置文件的响应消息,=后面是中文的unicode编码的iso8859-1的表示形式,通过视图可以直接配置,也可以用java/bin目录下的native2ascii.exe工具进行转码

    多文件上传
        出现有多个文件共同上传时,文件拦截器会出现一错全错的情况,这时我们利用struts的一个
                小bug---文件拦截不成功也调用action类的setXxx方法传入文件,从set函数中对文件进行筛选和转存
                这时文件拦截器已经形同虚设,一点作用也不起了。

    原理过程
        1.上传请求经过struts2的过滤器匹配扩展名
        2.按src/struts.xml文件中声明的配置包映射的名称空间映射到配置包
        3.根据action标签的name属性匹配名称空间与扩展名之间的“文件名”,映射到该action标签
                1> 经过多层拦截器
                2> 用param标签注入文件存储路径
                3> 通过<interceptor-ref name="fileUpload">标签对上传文件进行参数上的限定
                2> 执行action标签对应类的方法,该方法返回的返回的字符串进行响应

    默认配置
        1.defaultStack拦截栈中的fileUpload拦截器进行处理
        2.default.properties配置文件中 对multipart的上传方式进行了配置
                struts.multipart.parser=jakarta                  # struts使用了第三方的jakerta来给上传文件解码
                struts.multipart.saveDir=                      # 缓存文件的临时目录,不填默认是
                                                                                        ## work/catalina/localhost/web工程名/upload_.....00000..tmp
                struts.multipart.maxSize=2097152      # 默认支持的上传文件的大小 (字节,2m),是总大小
        3.多数服务器自己删除缓存文件
## 下载
    用传递类型为stream 来返回要下载的文件
    写法
        <result name="success" type="stream">
            <!-- 下载文件的类型 -->
            <param name="contentType">image/pjpeg</param>
            <!-- byte[]的大小,单位字节 -->
            <param name="bufferSize">2048</param>
            <!-- 设置下载响应头,${uuidFileName}是一个OGNL表达式,不是EL表达式 -->
            <param name="contentDisposition">attachment;filename=${uuidFileName}</param>
            <!-- 框架调用getXxx()方法,来获取InputStream流对象 -->
            <param name="inputName">imageStream</param>
        </result>
            # 与其它同样,要注入的参数从stream类型对应的类中可以进行查看
    显示与下载的编码问题
        o-> 设置tomcat/conf/server.xml
            <Connector port="8080" .. URIEncoding="utf-8"/>
        o-> 提交下载请求用post方式,struts框架自动给post请求编码解码

数据 #

日志 #

scribe
    facebook出品
    特点
        支持nfs存储
    结构
        scribe agent
            向scribe发送数据
        scribe
            接收数据,不同topic 的数据发送给不同的store中
        存储系统(store)
            file, buffer, network, bucket, null, thriftfile, multi
chukwa
    # apache出品,hadoop系列产品
flume
    cloudera出品
    特点
        可靠性(节点故障时,日志传送到其他节点)
            三种级别
                end-to-end 发送前写磁盘,成功时删除
                store on failure 失败返回时写磁盘
                best effort 不确认数据是否成功
        可扩展性
            agent collector storage三层架构,每层可扩展。
                agent: 将数据源数据发送给collector
                collector: 将多个agent数据汇总后, 加载到storage中
                storge: 存储系统, 可以是file, hdfs, hive, hbase等
            agent collector 由master统一
logstash
    # 分布式日志收集,需结合kafka

爬虫 #

cheerio
    # node解析html,如jquery
scrapy-redis
    # python 分布式爬虫框架
phantomjs
    # js浏览器模拟框架

分析 #

pandas
    # python数据分析

计算 #

druid
    # apache
    特点
        分布式, 扩展性强
        高可用,可回滚
        内存, 时序数据库
        亚秒级OLAP,  实时分析
        多租户
spark
stream
hadoop

搜索 #

分类
    垂直搜索引擎
        针对某一个行业的专业搜索引擎,是搜索引擎的细分和延伸,是对网页库中的某类专门的信息进行一次整合,定向分字段抽取出需要的数据进行处理后再以某种形式返回给用户。
    通用搜索引擎
        通过关键字的方式实现的,是语义上的搜索,返回的结果倾向于知识成果,比如文章,论文,新闻等
        通用搜索引擎的信息量大、查询不准确、深度不够
        通用搜索引擎的海量信息无序化

部分
    1.索引
    2.分词
    3.搜索

compass
    # 基于lucene
nutch
    # 基于lucene
sunspot
    # 基于Rsolr,以dsl结构用ruby调solr
sphinx
    # 基于sql的全文检索引擎

lucene #

# 原理
    block k-d tree
    倒排索引
        词典
            排序数组
                # 为了二分查找
                # 实现简单,性能差
            哈希表
                # 性能好,占内存大
            跳跃表
                # 内存小且可调节, 模糊查询不好
            B/B+树
                # 磁盘索引 ,更新方便,检索慢
            trie树
                # 效率与字符串长度有关,只适合做英文词典
            dat
                # 可做中文词典,内存占用小
            fst
                # 共享前缀,内存占用小,要求输入有序,不易更新
                内存存前缀索引、磁盘存后缀词块
        倒排表
        正向文件
            # 行式存储,原始文档
        doc-values
            # 列式存储,文档号到值的映射
    文件指纹

# 概念
    index
        # 一个倒排表,对应一个目录
    segment
        # index的存储单元,包含多个文档
    document
        # 创建单位
    field
        # 文档里的键值对
    term
        # 分词后的字符串
    analyzer
        tokenizer
            # 切分文本到索引单元
        tokenfilter
            # 对token预处理
# 常识
    特性
        索引
        高亮
        命中率排序
        分词
    与数据库的区别:数据库注重存储、全文检索注重查询
    其它搜索:多媒体搜索
    索引库(文件夹 或 内存中):
        只存储了商品的基本信息
         索引库与数据库定时同步
        索引库 -> document -> field                # field是键值对,值只能存数据
                同步
        IndexWriter:addDocumnet(),delteDocument(),updateDocument()
                查询
                        IndexSearch:search(),get()
        Field的内部结构
                    # 不存不索引会报错
        Store:控制此Field字段是否存储到索引库中
        Index:是否建立索引(索引不区分大小写,过滤词不创建索引)
            NO:不建立索引,可以通过field的key查到,但是不能通过关键字查询到
            NOT_ANALYZED:建立索引,但是不分词
            ANALYZEd:建立索引又分词
# 使用到的对象
    Directory
    Analyzer
        TokenStream tokenStream = analyzer.tokenStream("eldName",new StringReader("测试字符串"))
        while(tokenStream.incrementToken()){
                TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);
                System.out.println(termAttribute.term());
        }                # 使用分词器测试分词
    Document
        add(Field)
        document = indexSearcher.doc(ScoreDoc)
        get(String)                # 通过key查找value
    IndexWriter
        IndexWriter(directory,analyzer,MaxFieldLength.LIMITED);       # LIMITED限定Field的数量(源码中规定默认值)
        addDocument(Document)
        commit()
        close()                        # 自带commit()
        rollback()
    IndexSearcher
    QueryParser
        QueryParser(Version.LUCENE_30,"name",analyzer)
    Query
        query = parser.parse(用户传递的字符串);
        query = parser.parseMultiField(String [], 用户传递的字符串);
    TopDocs
        topDocs = indexSearcher.search(query, 10);                # 10是期望的结果数
                                                                                                        ## 最终查询到的结果数是:期望结果数与实际结果数的最小值
        totalHits                # 命中的结果数
    ScoreDoc
        ScoreDoc [] scoreDocs = topDocs.scoreDocs;
        scoreDoc.score                # 命中率积分
        scoreDoc.doc                # 命中文档编号,该编号由lucene自动生成
    Term                # 索引项
        Term("field中的key","field中value解析出的关键字")
# 索引的结构
    Term("key","value")[0,3,4]                        # key 为对应的field中的"key",value对应的是解析field的"value"出的关键字
                                                                                ## []中的内容为匹配的文档编号,该编号为系统自动生成的
# 注意
    lucene创建索引时field的key都可以重复,没有主键方面的限制。但是实际应用时要求我们为document有唯一的标识“主键”field,便于对每个document进行更新与删除
# 使用
    包:IKAnalyzer,lucence-analyzer(英文分词,不需要),memory,core,highlighter
    工具:lukeAll 用来查看索引库
    添加、查询、删除、修改
    抽取配置类(构造方法私有化)
        Configuration
            维护了directory与analyzer
        DocumentUtil
            goodsToDocument(Goods)
            documentToGoods(Document)
        LuceneUtil
            维护了indexWriter与indexSearcher
            注意
                    1.indexWriter在static代码块中初始化
                    2.getIndexWriter
        LuceneService
            用indexWriter与indexSearcher处理业务逻辑
            添加
                indexWriter.addDocument(Document)
                indexWriter.rollback()
            删除
                indexWriter.deleteDocument(Term)
                indexWriter.optimize()                # 删除document的时候同步索引库,没有设置的话只是删除document,但是索引中还是可以查到
            更新
                indexWriter.updateDocument(Term,Document)
                indexWriter.optimize()                # 更新是先删除再添加(所以如果updateDocument(Term,Document)中匹配多个Document时,会出现删除了多个Document,而添加了一个Document的情况)
            查询
                QueryParser parser = new QueryParser(Version.LUCENE_30, "field中的key", analyzer);
                Query query = IKQueryParser.parseMultiField(new String[]{"name","remark"}, "ee");                # 多字段查询,IKAnalyzer特有
                    # 多字段查询到的第二个字段的结果,在转换高管时(调用getBestFragment时)只会对该方法指定的一个字段进行匹配,如果该字段不匹配时(但是第二个字段匹配),则会返回空。
                    ## 针对这一个bug,在getBestFragment处理匹配的结果返回空时,不使用空而直接返回没有高亮的字符串即可。
                parser.parse(用户传递的字符串);
                TopDocs topDocs = indexSearcher.search(query, 3);        # 3是期望结果数
                ScoreDoc [] scoreDocs = topDocs.scoreDocs;
                Document document = indexSearcher.doc(scoreDoc.doc);                scoreDoc.doc得到文档编号
                分页查询:
                    传递当前页码与一页记录数
                    利用topDocs.totalHits得到总记录数
                    查询本页与前面所有页的期望数据量,然后只截取本页的文档编号,得到document并返回数据

# 分词器
    IKAnalyzer
        配置文件
            src/IKAnalyzer.cfg.xml中配置
                <properties>
                    <entry key="ext_dict">/mydict.dic</entry>                 # 配置自己的字典(不分词)
                    <entry key="ext_stopwords">/ext_stopword.dic</entry>                 # 配置跳过的字
                </properties>
        Query query = IKQueryParser.parse("name",name);                # IKAnalyzer特有
# 排序
    Directory directory = FSDirectory.open(new File("d:/lucene"));
    IndexSearcher indexSearcher = new IndexSearcher(directory);
    Query query = IKQueryParser.parse("name","cc");
    Sort sort = new Sort(new SortField("id", SortField.INT,true));                # 这里可以排序多个字段
        # 参数1:"id"是排序的field字段,参数2:是字段内容的类型,参数3 true代表降序排列
        ## 此时命中率不再计算(因为不按命中率排序)
        ## 排序的field必须建立索引
    indexSearcher.search(query, null,10,sort);
高亮
    导入包:highlight与memory
    Highlighter highlighter = new Highlighter(new SimpleHTMLFormatter("<font color='red'","</font>"),new QueryScorer(query));
    highlighter.setTextFragmenter(new SimpleFragmenter(10));                # 限制字符长度
    ..
    String result = highlighter.getBastFragment(analyzer,"name",doc.get("name"));
        # 返回高亮处理字符串
        ## 参数1:解析用户输入词的分词器,参数2:是要查询的field的key(没有用),参数3:field的value

solr #

介绍
    基于lucene
    搜索服务器,http请求提交和返回xml
功能
    丰富了查询语言
    实现可配置、可扩展
    优化了性能
    提供了管理界面
    缓存功能
    垂直搜索
    高亮
    data schema定义字段

elasticsearch #

介绍
    基于lucene
性能
    第一次查秒级响应(5-10秒),放到文件系统缓存(filesystem cache)
    再查命令缓存毫秒级响应                              # 热点数据要预热
    文件系统缓存(内存中分配)和数据量同样大,才有效率        # 冷热分离

    分页,会查前面所有数据                              # 用scroll api, 快照 + 游标

权限 #

shiro #

功能
    认证
    授权
    加密
    会话管理
    Web集成
    缓存
组件
    Subject     # 当前用户,绑定到SecurityManager
    SecurityManager     # 门面模式,管理组件
    Realms      # 连接认证数据(用户、角色、权限)
    Authenticator   # 认证principals和credentials
    Authorizer  # 校验权限
    SessionManager      # 异构客户端
控制方式
    url
    注解
    代码
    页面标签
模块
    Authenticator
        # SecurityManager继承Authenticator
        public AuthenticationInfo authenticate(AuthenticationToken authenticationToken)  throws AuthenticationException;
    permission
        概念
            subject
            resource
            permission
            role
                隐式角色
                显示角色
        配置
            shiro.ini
                [users]
                zhang=123, role1, role2                # 用户名=密码, 角色1, 角色2
        判断角色
            o->
                subject.hasRole("admin");
            o->
                @RequiresRoles("admin")
                @RequiresRoles(value={“admin”, “user”}, logical= Logical.AND)
                    # 表示当前Subject需要角色admin和user。
            o->
                <shiro:hasRole name="admin"></shiro:hasRole>
        权限注解
            @RequiresAuthentication
                # 表示当前Subject已经通过login进行了身份验证;即Subject. isAuthenticated()返回true。
            @RequiresUser
                # 表示当前Subject已经身份验证或者通过记住我登录的。
            @RequiresGuest
                # 表示当前Subject没有身份验证或通过记住我登录过,即是游客身份。
            @RequiresPermissions (value={“user:a”, “user:b”}, logical= Logical.OR)
                # 表示当前Subject需要权限user:a或user:b。
    credential
        散列
            String str = "hello";
            String salt = "123";
            //内部使用MessageDigest
            String simpleHash
        密码生成工具
            //输入明文密码得到密文密码
            String encryptPassword(Object plaintextPassword) throws IllegalArgumentException;
            //匹配用户输入的token的凭证(未加密)与系统提供的凭证(已加密)
            boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info);
    filter
        NameableFilter                        #根据名字找到相应的拦截器实例
        OncePerRequestFilter                # 控制开启、关闭拦截器实例
        ShiroFilter                        # 安全控制
        AdviceFilter                        # aop
            preHandle                        # 前置增强
            postHandle                        # 后置增强
            afterCompletion                # 后置最终增强(异常也执行,相当于finally的概念)
        PathMatchingFilter                # 匹配请求路径
        AccessControlFilter                # 允许或拒绝访问,拒绝时如何处理
    jsp标签
        <%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

        <shiro:guest>
        欢迎游客访问,<a href="${pageContext.request.contextPath}/login.jsp">登录</a>
        </shiro:guest>

        <shiro:user>
        欢迎[<shiro:principal/>]登录,<a href="${pageContext.request.contextPath}/logout">退出</a>
        </shiro:user>
            # 用户已经身份验证/记住我登录后显示相应的信息。

        <shiro:authenticated>
            用户[<shiro:principal/>]已身份验证通过
        </shiro:authenticated>
            # 用户已经身份验证通过,即Subject.login登录成功,不是记住我登录的。

        <shiro:notAuthenticated>
            未身份验证(包括记住我)
        </shiro:notAuthenticated>
            # 用户已经身份验证通过,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证。

        <shiro: principal/>
            # 显示用户身份信息,默认调用Subject.getPrincipal()获取
            <shiro:principal type="java.lang.String"/>
            <shiro:principal property="username"/>

        <shiro:hasRole name="admin">
            用户[<shiro:principal/>]拥有角色admin<br/>
        </shiro:hasRole>

        <shiro:hasAnyRoles name="admin,user">
            用户[<shiro:principal/>]拥有角色admin或user<br/>
        </shiro:hasAnyRoles>

        <shiro:lacksRole name="abc">
            用户[<shiro:principal/>]没有角色abc<br/>
        </shiro:lacksRole>
                        # 如果当前Subject没有角色将显示body体内容。

        <shiro:hasPermission name="user:create">
            用户[<shiro:principal/>]拥有权限user:create<br/>
        </shiro:hasPermission>

        <shiro:lacksPermission name="org:create">
            用户[<shiro:principal/>]没有权限org:create<br/>
        </shiro:lacksPermission>
    session
        得到会话
            login("classpath:shiro.ini", "zhang", "123");
            Subject subject = SecurityUtils.getSubject();
            Session session = subject.getSession();
        api
            Session
                getId()
                getHost()                # 调用HostAuthenticationToken.getHost(), 得到主机地址
                getTimeout()
                setTimeout(1000)
                getStartTimestamp()
                setLastAccessTime()
                touch()                        # 更新会话最后访问时间
                stop()                        # 销毁会话, Subject.logout()与HttpSession.invalidate()会自动调用该api
                setAttribute("key", "123")
                getAttribute("key")
                removeAttribute("key")
            SecurityManager
                Session start(SessionContext context)
                Session getSession(SessionKey key) throws SessionException
            WebSessionManager
                boolean isServletContainerSessions();                # 是否使用Servlet容器的会话
            ValidatingSessionManager
                void validateSessions();                                # 验证所有会话是否过期
    cache
        接口
            Cach<K, V>
            CacheManager
            CacheManagerAware
        ini配置
            userRealm.cachingEnabled                        # 启用缓存,默认false
            userRealm.authenticationCachingEnabled        # 启用身份验证缓存,即缓存AuthenticationInfo信息,默认false
            userRealm.authenticationCacheName                # 缓存AuthenticationInfo信息的缓存名称
            userRealm. authorizationCachingEnabled        # 启用授权缓存,即缓存AuthorizationInfo信息,默认false
            userRealm. authorizationCacheName                # 缓存AuthorizationInfo信息的缓存名称
            securityManager.realms=$userRealm

            cacheManager=org.apache.shiro.cache.ehcache.EhCacheManager
            cacheManager.cacheManagerConfigFile=classpath:shiro-ehcache.xml
            securityManager.cacheManager=$cacheManager

            sessionManager=org.apache.shiro.session.mgt.DefaultSessionManager
            securityManager.sessionManager=$sessionManager
    rememberme
    ssl
        o-> keytool -genkey -keystore "D:\localhost.keystore" -alias localhost -keyalg RSA
            # jdk自带的生成证书工具(包含证书/公钥/私钥)
        o-> 设置tomcat server.xml
            <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
            maxThreads="150" scheme="https" secure="true"
            clientAuth="false" sslProtocol="TLS"
            keystoreFile="D:\localhost.keystore" keystorePass="123456"/>
        o->
    jasig cas
api
    Subject: 主体, 如用户
    SecurityManager: 安全管理器, 管理subject
    Realm: 权限数据域

    授权
        对象流程
            Subject.isPermitted -> SecurityManager -> Authorizer
        对象
            ModularRealmAuthorizer        # 多realm授权
            PermissionResolver                # 解析权限字符串到Permission实例
            RolePermissionResolver                # 从角色得到权限集合
配置
    参数
        filterChainDefinitions
            rest:比如/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。

            port:比如/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。

            perms:比如/admins/user/**=perms[user:add:*],perms参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,比如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。

            roles:比如/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,比如/admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。

            anon:比如/admins/**=anon 没有参数,表示可以匿名使用。

            authc:比如/admins/user/**=authc表示需要认证才能使用,没有参数

            authcBasic:比如/admins/user/**=authcBasic没有参数表示httpBasic认证

            ssl:比如/admins/user/**=ssl没有参数,表示安全的url请求,协议为https

            user:比如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
                    # remember me可登录

分布式 #

redisson #

介绍
    使用redis外部存储,实现分布式功能