一、feign使用
    openFeign:调用远程就像调用本地一样
    协议:http协议
    底层技术:httpclient

    服务注册发现:
    https://nacos.io/zh-cn/

    案例一:
    电影票购买系统,包括组件:销售、订单、电影院—每个系统对应自己独立数据库
    1、销售系统从电影院拉取正在上映的电影票——>销售
    电影系统只需在数据库中手动放入电影票,销售获取到电影票后需要先保存到本地数据库,再展示到页面
    2、用户下单后把订单保存到订单系统
    3、用户在销售系统可以查看自己的订单

    用户能看到的系统是:销售系统

    1、springcloud的版本需要和springboot的版本匹配(www.spring.io)

    2、springcloud —->open fegin —->调用远程就像调用本地代码一样
    fegin: 是http协议

    post请求的数据 需要加@RequestBody 注解,从body取数据

    3、任何代码如果重复拷贝三次那么就需要考虑重构(封装)

    4、定时调度:-spring自带定时调度器
    @EnableScheduling 开启定调度

    二、微服务治理一、注册发现

    1、服务发现治理——->把微服务向注册服务器注册——->微服务之间的访问通过注册服务器发现
    我们用的技术是阿里的nacos
    nacos 使用

    1、创建nacos数据库,并创建表初始化数据
    2、在application.properties 进行配置
    server.port=8848 #配置端口号 8848 是世界最高峰的高度

    db.url.0=jdbc:mysql://192.168.244.11:3306/J185_nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
    db.user.0=root
    db.password.0=1234
    3、把nacos-mysql.sql 配置文件导入到新建的数据库
    4、进入bin文件夹,执行【单机启动.bat】
    5、访问nacos地址http://192.168.60.1:8848/nacos/index.html,
    默认账号为nacos 密码为nacos
    6、在项目中引入服务发现的坐标

    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-discovery
    2.2.4.RELEASE

    6、在配置文件中配置nacos地址,给应用程序取一个名字
    spring:
    application:
    name: movieSys
    cloud:
    nacos:
    discovery:
    server-addr: 127.0.0.1:8848
    三、MQ消息队列

    1、队列 ——>线性结构 先进先出 (相对数组来说就是只有添加、删除)
    应用的场景:生产者和消费者模式 ——>消峰的作用
    队列是一个异步的处理——->把一件事情分成两步来实现
    主流的mq: kafka、rabbitmq、rocketmq、activemq

    docker run -d -p 5672:5672 -p 15672:15672 —name rabbitmq rabbitmq:management
    #5672 tcp/IP端口—代码中使用 15672 是http的端口—-控制台
    MQ 进行对象传输的时候需要进行序列化和反序列—->因为它是TCP/IP协议

    //spring封装rabiitmq的代码 RabbitTemplate
    //注入工厂(已经预加载)
    @Autowired
    CachingConnectionFactory connectionFactory;
    //rabbitmq模板
    @Bean(value = “rabbitTemplate”)
    public RabbitTemplate rabbitTemplate(){
    return new RabbitTemplate(connectionFactory);
    }

    作业: 1、用户下单后需要把订单保存到订单系统,状态改0(支付成功未出票),返回给用户
    2、把订单通过MQ发送到电影系统,电影系统根据电影名修改票数(出票),并把订单保存到电影院系统
    3、电影院系统通过fegin调用订单系统接口,把订单修改为1(出票成功)或2(出票失败)
    RabiitMQ交换机:
    1、默认交换机:DirectExchange —->交换机名+路由KEY
    2、主题交换机: TopicExchange——->交换机名+路由KEY(模糊匹配)
    *(星号)可以代替一个单词
    #(井号)可以代替零个或多个单词
    3、扇型交换机 FanoutExchange ——->广播模式(订阅发布模式),不需要key,把消息投递到绑定的队列中去
    4、头交换机 —->把规则放到发送内容中

    注意:队列尽量不要绑定到不同的交换机,一个交换机是允许绑定多个队列

    在rabbitmq中如何保证数据不丢失?

    spring:
    rabbitmq:
    host: 172.16.1.253
    port: 5672
    username: admin
    password: 123456
    publisher-confirm-type: correlated
    virtual-host: /
    listener:
    simple:
    acknowledge-mode: manual #开启ACK
    retry:
    max-attempts: 5 #重试次数
    initial-interval: 5000 #重试间隔时间
    enabled: true #开启消费重试
    default-requeue-rejected: false #重试次数超过
    生产者:
    RabbitTemplate.ConfirmCallback callback=(CorrelationData correlationData, boolean b, String s)->{

    }

    //开启手动确认
    rabbitTemplate.setMandatory(true);//开启消息确认
    //绑定回调函数
    rabbitTemplate.setConfirmCallback(callback);
    //创建关联数据对象
    CorrelationData correlationData=new CorrelationData(orderNum);

    死信

    练习: 下单后弹出一个窗口,显示正在支付(需要有正在加载的效果,页面等待5秒钟),当消息投递到队列后,加载效果消失,显示支付成功等待出票或 支付失败 或出票成功

    四、治理二、负载均衡 - —->冗余

    负载均衡——->1、分摊IO流 2、灾备
    常用的负载均衡算法:1、轮询 2、ip_hash 3、hash一致算法
    Netflix -ribbon 组件来实现的负载均衡

    第五、治理三、熔断

    熔断———>服务降级处理——->避免服务雪崩
    Netfilx -hystrix 组件
    @EnableCircuitBreaker //开启熔断

    @HystrixCommand(fallbackMethod = “twoInfoHystrix”)
    public String twoInfo(int tag){
    return service.twoInfo(tag);
    }

    1. public String twoInfoHystrix(int tag){
    2. return "系统暂时无法访问";
    3. }

    @FeignClient(name = “sysTwo”,fallback = TwoHystrixService.class)

    //要开启feign熔断机制
    feign:
    hystrix:
    enabled: true
    第六服务治理四-集中配置

    1、 把所有微服务的配置放到一个服务器上,进行集中配置
    2、我们用nacos来做集中配置服务

    springboot 默认配置: bootstrap application 前者会优先启动
    后缀: properties yml 前者优先与后者

    spring:
    application:
    name: sysOne
    cloud:
    nacos:
    config:
    server-addr: 172.16.1.253:8848
    file-extension: yml
    prefix: sysOne
    profiles:
    active: dev
    第七服务治理五-网关

    网关用springcloud —->gateway (所用的框架是springweb flow 来实现的MVC)
    网关做的事情:1、过滤 2、路由

    作业:

    1、销售、订单、电影院 需要注册发现和集中配置
    2、通过网关:1、查询用户的所有订单——>订单系统
    2、查询所有电影票——->电影票系统
    3、查询正在出售的电影——>销售系统

    第八服务治理日志处理

    第九-redis

    redis 是非关系型数据库(NO-SQL),是内存数据库,但可以持久化。语法 key-val
    redis新版 默认是单线程-所以是线程安全

    启动redis服务: redis-server 配置文件名
    启动redis客户端:redis-cli -p 端口 -h 服务器地址 -a 认证

    docker run -d —name redis -p 6379:6379 redis #docker 安装redis
    1 、String

    set key  val   -->添加
     get key     --->查询
     del key--->删除 (通用)
    

    setex key seconds val —设置过期时间 在分布式中可以做全局session
    2、hash—->存储对象 ——java(Map集合)

    1、 HSET key field value 添加
    2、 HGET key fied —->查询
    3、 HDEL key filed —->删除某个字段
    4、del key —->删除所有
    5、hmset key filed val filed val 批量添加

    3、List——>队列 —->生产者和消费者(消峰)
    队列是一个线型的数据结构,做了一个特殊的处理(先进(放入)先出(删除))
    程序中的场景:生产者和消费者模型

    (L)Rpush key val—->放
    (L)RPOP key —->取
    B(L)RPOP key timeout ——>阻塞的取

    4、无序集合 —->交集、差集—->(共同好友、推荐好友)
    sadd key val val —->添加
    sinter key1 key2 ——>交集
    sdiff key1 key2 ——->差集

    5、有序集合 —->排序—->排行榜
    zadd key score val score val….. 添加
    ZINCRBY key increment member
    有序集合中对指定成员的分数加上增量 increment
    排序:zrange key start stop (-1,代表全部) 升序
    zrevrange key start stop (-1,代表全部) 降序

    redis 可以用来做什么?
    1、分布式session
    2、分布式协调机制(单线程,数据安全)
    3、缓存
    4、存储对象
    5、生产者消费者模型(队列、栈—->可以是阻塞式)
    6、交集差集(共同好友、推荐好友)
    7、排行榜
    java 操作redies

    org.springframework.boot
    spring-boot-starter-data-redis

    io.lettuce
    lettuce-core

      <dependency>
          <groupId>redis.clients</groupId>
          <artifactId>jedis</artifactId>
          <version>3.3.0</version>
      </dependency>
      <dependency>
          <groupId>org.redisson</groupId>
          <artifactId>redisson</artifactId>
          <version>3.5.0</version>
      </dependency>
      <dependency>
          <groupId>io.netty</groupId>
          <artifactId>netty-all</artifactId>
          <version>4.1.25.Final</version>
      </dependency>
      <dependency>
          <groupId>com.google.guava</groupId>
          <artifactId>guava</artifactId>
          <version>29.0-jre</version>
      </dependency>
    

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
    RedisTemplate template = new RedisTemplate<>();
    template.setConnectionFactory(factory);

    // 使用Jackson2JsonRedisSerialize 替换默认的jdkSerializeable序列化
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);
    
    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    
    // key采用String的序列化方式
    template.setKeySerializer(stringRedisSerializer);
    // hash的key也采用String的序列化方式
    template.setHashKeySerializer(stringRedisSerializer);
    // value序列化方式采用jackson
    template.setValueSerializer(jackson2JsonRedisSerializer);
    // hash的value序列化方式采用jackson
    template.setHashValueSerializer(jackson2JsonRedisSerializer);
    template.afterPropertiesSet();
    return template;
    
    }
    

    练习:在电影票销售系统,从数据库查询出需要销售的电影票,放到页面销售。
    1、首先判断缓存是否存在电影票,如果不存在就从数据库中查询出来,先放入缓存再返回到页面。
    如果缓存中存在就直接返回到页面。缓存时间为5秒。(string)
    2、在页面加一个添加到购物车按钮,把信息放入到redis,可以对购物车信息进行 修改数量,删除某张电影票
    (hash)

    十、缓存

    设置缓存的KEY需要根据查询条件来设置
    @GetMapping(“movieEntityList/{price}/{tag}”)
    public Object movieEntityList(@PathVariable(“price”)float price,
    @PathVariable(“tag”)int tag){
    String key=price+”-“+tag;
    }
    jmeter summary report 字段意思
    Samples :事务数量
    Average:平均一个完成一个事务消耗的时间(平均响应时间)
    Median:所有响应时间的中间值,也就是 50% 用户的响应时间,大概是这个意思
    Min:最小响应时间
    Max:最大响应时间
    以上单位都是ms
    Std.Dev:偏离量,越小表示越稳定
    Error %:错误事务率
    Throughtput:每秒事务数,即tps
    KB/sec:网络吞吐量
    Received KB/sec :每秒从服务器端接收到的数据量(每秒发送多少字节 )
    Sent KB/sec :每秒向服务器发送数据量(每秒发送多少字节 )

    1、缓存雪崩
    if(!redis.hasKey(key)){
    List list=movieDao.findAllByPriceAndTag(price,tag);
    if(null!=list){
    //防止缓存雪崩
    int timeCache=ToolUtil.MIN_CACHE_TIME;
    long time=(System.currentTimeMillis()+key.hashCode())%ToolUtil.CACHE_TIME;
    if(time>ToolUtil.MIN_CACHE_TIME){
    timeCache=(int)time;//最小值—-最大值之间的数
    }
    redis.set(key,list, timeCache);
    }
    }
    2、缓存穿透
    public static BloomFilter bloomFilter;
    static {

        //布隆过滤器,,实现项目中可以在用户添加数据或修改数据的时候放入数据
        bloomFilter= BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()),1000000,0.001);
        bloomFilter.put("120.0-0");
        bloomFilter.put("130.0-0");
    }
    
    String key=price+"-"+tag;
        //过滤器
         if(!ToolUtil.bloomFilter.mightContain(key)){
             //非法
             return null;
        }
    

    //解决方式
    1、把null对象也放入缓存,设置较短的缓存时间
    2、加布隆过滤器,只允许过滤器中有点条件才进入。
    3、缓存击穿

    锁—->肯定用在大并发/多线程——>有序的去操作公共资源——>会导致效率降低——>一定不要出现死锁
    @Bean
    public RLock rLock() {
    Config config = new Config();
    SingleServerConfig singleServerConfig = config.useSingleServer();
    singleServerConfig.setAddress(“redis://172.16.1.253:” + 6379);
    singleServerConfig.setTimeout(3000);
    // singleServerConfig.setDatabase(database);
    // singleServerConfig.setPassword(“123456”);
    RLock rLock= Redisson.create(config).getLock(“J185”);
    return rLock;
    }

    促销系统:
    1、 拿出100张电影票来进想促销。用户点击抢购电影票,点击后按钮变为不可操作并弹出窗口等待是否抢购成功。
    2、用户购买订单放入到队列MQ
    3、系统获取队列订单,每2张电影票取一张为成功信息。并把成功信息放入到redis(用户ID+订单)
    4、用户等待10秒钟,如果10秒钟在redis没有获得信息为抢购失败,否则为成功
    5、活动结束后,写一个定时调度器,把redis信息持久化到关系型数据库
    索引数据库ES
    1、访问ES服务器用http协议
    2、索引数据库-提供全文搜索

    索引:让查询效率更快
    检索内容——>先找索引—->索引对应的内容
    1、索引会占用物理空间
    2、索引会让修改变慢

    数据库的索引:聚集索引和非聚集索引

    聚集索引:数据库自动创建—->第一个不为空的字段(ID)
    非聚集索引:我们创建的索引

    非聚集索引——>找聚集索引—->找真实的数据

    1、经常查询的列上建索引

    2、索引失效:
    1.查询条件中有or,即使有部分条件带索引也会失效
    2.like查询是以%开头
    3、sql函数不会用索引
    4.违背最左匹配原则
    age的索引是和建立再(name,age)组合索引的基础上,当查询条件中没有第一个组合索引的字段(name)会导致索引失效
    5、大文本不能使用索引 ——>会导致索引空间快速增加

    全文搜索:把文章里面的 字或词组建索引——->检索出文章

    org.springframework.boot
    spring-boot-starter-data-elasticsearch

    spring:
    elasticsearch:
    rest:
    uris: http://172.16.1.254:9200
    @Data
    @Document(indexName = “news_index”)
    public class NewsEntity {
    @Id
    @Field(type=FieldType.Keyword) //不建索引
    private String newsId;
    @Field(type = FieldType.Text)
    private String newsInfo;
    @Field(type=FieldType.Keyword) //不建索引
    private String newsDate;

    }

    public interface INewsDao extends PagingAndSortingRepository {

    public List<NewsEntity> findAllByNewsInfo(String info);
    

    }

    作业:秒杀系统没有命中的客户订单放入到ES——>时间+地区+购买的商品信息
    在页面上可以实现全文搜索

    服务治理八-日志治理
    ELK
    Logstash主要是用来负责搜集、分析、过滤日志的工具,支持大量的数据获取方式。一般工作方式为c/s架构,client端安装在需要收集日志的主机上,server端负责将收到的各节点日志进行过滤、修改等操作在一并发往elasticsearch上去。
    ElasticSearch用来负责存储最终数据、建立索引和对外提供搜索日志的功能。它是个开源分布式搜索引擎,提供搜集、分析、存储数据三大功能。它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等。
    Kibana是一个优秀的前端日志展示框架,它可以非常详细的将日志转化为各种图表,为用户提供强大的数据可视化支持。

    系统日志功能

    org.springframework.boot
    spring-boot-starter-logging

    logging:
    file:
    path: d:/log
    level: #TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
    com.lovo.*: debug
    @Slf4j //需要日志的地方

    log.info(“testLog,日志”);
    连接池:
    认识连接池:因为创建连接本身就是一个耗时工作,即便是不进行数据交互。连接池是预先创建一部分连接进入连接池,然后管理连接池中连接的生命周期。

    1、初始化连接数
    2、增量数
    3、最大连接数
    4、空闲时间
    5、最小连接数
    6、连接等待时间
    hikari:
    minimum-idle: 5
    # 空闲连接存活最大时间,默认600000(10分钟)
    idle-timeout: 180000
    # 连接池最大连接数,默认是10
    maximum-pool-size: 10
    # 此属性控制从池返回的连接的默认自动提交行为,默认值:true
    auto-commit: true
    # 连接池名称
    pool-name: MyHikariCP
    # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
    max-lifetime: 1800000
    # 数据库连接超时时间,默认30秒,即30000
    connection-timeout: 30000
    connection-test-query: SELECT 1

    服务治理九-认证

    1、token来做单点登录
    2、auth2.0

    3、token ——>分布式的回话跟踪<———http协议是短连接无状态

    4、会话跟踪: session 重新URL token(header)

    练习:1、写一个认证系统实现登录,创建token
    2、前端登录后把token放入到sessionStroe
    3、前端访问订单系统、访问电影院系统,携带token去访问
    4、电影院和订单系统对token进行认证,认证成功才返回数据

         5、用户拥有2个权限-1为电影系统 2-订单系统
         6、用户登录成功随机给用户分配一个权限
         7、电影院或订单系统,在拦截器中获取到header中的token
          8、先现在token是否合法,再验证用户是否拥有访问该系统的权限,如果通过放行返回数据,否则返回错误结果。
    

    Nginx

    1、web服务器
    2、正向代理 —->网关
    springcloud gateway 也是网关 如何选择?
    如果需要用JAVA代码来写业务逻辑就要用gateway, 如果只是做路由是可以相互替换

    3、反向代理 ——->负载均衡

    主从分离

    数据库的负载均衡

    拆表

    1、mycat中间件的配置—>server.xml

    druidparser

    </system>
    <user name="root">
        <property name="password">123456</property>
        <property name="schemas">mycatDB</property>
    </user>
    

    表的配置:schema.xml

    <schema name="mycatJ185" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1,dn2">
        <!-- name    表名,物理数据库中表名
    

    dataNode 表存储到哪些节点,多个节点用逗号分隔。节点为下文dataNode设置的name
    primaryKey 主键字段名,自动生成主键时需要设置
    autoIncrement 是否自增
    rule 分片规则名,具体规则下文rule详细介绍
    type 该属性定义了逻辑表的类型,目前逻辑表只有全局表和普通表。全局表: global 普通表:无
    注:全局表查询任意节点,普通表查询所有节点效率低
    autoIncrement mysql对非自增长主键,使用last_insert_id() 是不会返回结果的,只会返回0.所以,只有定义了自增长主键的表,才可以用last_insert_id()返回主键值。
    mycat提供了自增长主键功能,但是对应的mysql节点上数据表,没有auto_increment,那么在mycat层调用last_insert_id()也是不会返回结果的。
    needAddLimit 指定表是否需要自动的在每个语句后面加上limit限制,由于使用了分库分表,数据量有时候会特别庞大,这时候执行查询语句,
    忘记加上limt就会等好久,所以mycat自动为我们加上了limit 100,这个属性默认为true,可以自己设置为false禁用。如果使用这个功能,最好配合使用数据库模式的全局序列。
    subTables 分表,分表目前不支持Join。—>

        <table name="sys_user" dataNode="dn1,dn2" rule="rule3" />
    <!--
    
        <table name="company" primaryKey="ID" dataNode="dn3,dn2,dn1" rule="mod-long"/>
        <table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" />
    
        <table name="hotnews" primaryKey="ID" dataNode="dn1,dn2,dn3"
            rule="mod-long" />
    
        <table name="employee" primaryKey="ID" dataNode="dn1,dn2"
            rule="sharding-by-intfile" />
        <table name="customer" primaryKey="ID" dataNode="dn1,dn2"
            rule="sharding-by-intfile">
        -->
        <!-- 1) childTable标签
    

    id
    func1

    <tableRule name="rule2">
        <rule>
            <columns>id</columns>
            <algorithm>func1</algorithm>
        </rule>
    </tableRule>
    
    <tableRule name="auto-sharding-rang-mod">
        <rule>
            <columns>id</columns>
            <algorithm>rang-mod</algorithm>
        </rule>
    </tableRule>
    
    <tableRule name="jch">
        <rule>
            <columns>id</columns>
            <algorithm>jump-consistent-hash</algorithm>
        </rule>
    </tableRule>
    
    <function name="murmur"
        class="org.opencloudb.route.function.PartitionByMurmurHash">
        <property name="seed">0</property><!-- 默认是0 -->
        <property name="count">2</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
        <property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
        <!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 -->
        <!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property>
            用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 -->
    </function>
    <function name="hash-int"
        class="org.opencloudb.route.function.PartitionByFileMap">
        <property name="mapFile">partition-hash-int.txt</property>
    </function>
    <function name="rang-long"
        class="org.opencloudb.route.function.AutoPartitionByLong">
        <property name="mapFile">autopartition-long.txt</property>
    </function>
    <function name="mod-long" class="org.opencloudb.route.function.PartitionByMod">
        <!-- how many data nodes -->
        <property name="count">3</property>
    </function>
    
    <function name="func1" class="org.opencloudb.route.function.PartitionByLong">
        <property name="partitionCount">2</property>
        <property name="partitionLength">512</property>
    </function>
    <function name="latestMonth"
        class="org.opencloudb.route.function.LatestMonthPartion">
        <property name="splitOneDay">24</property>
    </function>
    <function name="partbymonth"
        class="org.opencloudb.route.function.PartitionByMonth">
        <property name="dateFormat">yyyy-MM-dd</property>
        <property name="sBeginDate">2015-01-01</property>
    </function>
    
    <function name="rang-mod" class="org.opencloudb.route.function.PartitionByRangeMod">
            <property name="mapFile">partition-range-mod.txt</property>
    </function>
    
    <function name="jump-consistent-hash" class="org.opencloudb.route.function.PartitionByJumpConsistentHash">
        <property name="totalBuckets">3</property>
    </function>
    

    敏捷开发:
    敏捷开发以用户的需求进化为核心,采用迭代、循序渐进的方法进行软件开发。在敏捷开发中,软件项目在构建初期被切分成多个子项目,各个子项目的成果都经过测试,具备可视、可集成和可运行使用的特征。换言之,就是把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态

    1.墨刀-极简超快的移动应用原型工具
    2.ProcessOn 在线作图工具,不用装Visio
    3.Principle 前Apple工程师打造的交互设计工具,快速制作丰富流程的应用交互动画
    4.摩客 —简洁高效的原型图设计工具
    5.Sketch —一款轻量易用的矢量设计工具
    6.Axure 老牌原型工具
    7.xiaopiu 国内优雅高效的在线APP原型工具
    8.Mockplus 支持全平台的快速原型设计工具
    9.百度脑图 百度出品的一款良心在线的思维导图工具
    10.principle主要做交互 集合了Sketch keynote flash等优点

    出文档:
    1、 需求文档(文字、图片、用例图)—-> 给客户看——->转换为概要设计
    2、概要设计(程序员看)——->业务脚本(输入、输出、处理)——>业务流程图——>原型图
    3、PD —->数据库物理模型
    4、接口文档(远程调用的接口)
    5、项目的规范