功能

小功能

名词 #

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外部存储,实现分布式功能