Nginx入门

本文目的是学习Nginx+Lua开发,对于Nginx基本知识可以参考如下文章:

nginx启动、关闭、重启

http://www.cnblogs.com/derekchen/archive/2011/02/17/1957209.html

agentzh 的 Nginx 教程

http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html

Nginx+Lua入门

http://17173ops.com/2013/11/01/17173-ngx-lua-manual.shtml

nginx 配置指令的执行顺序

http://zhongfox.github.io/blog/server/2013/05/15/nginx-exec-order/

nginx与lua的执行顺序和步骤说明

http://www.mrhaoting.com/?p=157

Nginx配置文件nginx.conf中文详解

http://www.ha97.com/5194.html

Tengine的Nginx开发从入门到精通

http://tengine.taobao.org/book/

官方文档

http://wiki.nginx.org/Configuration

Lua入门

本文目的是学习Nginx+Lua开发,对于Lua基本知识可以参考如下文章:

Lua简明教程

http://coolshell.cn/articles/10739.html

lua在线lua学习教程

http://book.luaer.cn/

Lua 5.1 参考手册

http://www.codingnow.com/2000/download/lua_manual.html

Lua5.3 参考手册

http://cloudwu.github.io/lua53doc/

Nginx Lua API

和一般的Web Server类似,我们需要接收请求、处理并输出响应。而对于请求我们需要获取如请求参数、请求头、Body体等信息;而对于处理就是调用相应的Lua代码即可;输出响应需要进行响应状态码、响应头和响应内容体的输出。因此我们从如上几个点出发即可。

接收请求

1、example.conf配置文件

Java代码  
  1. location ~ /lua_request/(\d+)/(\d+) {
  2. #设置nginx变量
  3. set $a $1;
  4. set $b $host;
  5. default_type "text/html";
  6. #nginx内容处理
  7. content_by_lua_file /usr/example/lua/test_request.lua;
  8. #内容体处理完成后调用
  9. echo_after_body "ngx.var.b $b";
  10. }

2、test_request.lua

Java代码  
  1. --nginx变量
  2. local var = ngx.var
  3. ngx.say("ngx.var.a : ", var.a, "<br/>")
  4. ngx.say("ngx.var.b : ", var.b, "<br/>")
  5. ngx.say("ngx.var[2] : ", var[2], "<br/>")
  6. ngx.var.b = 2;
  7. ngx.say("<br/>")
  8. --请求头
  9. local headers = ngx.req.get_headers()
  10. ngx.say("headers begin", "<br/>")
  11. ngx.say("Host : ", headers["Host"], "<br/>")
  12. ngx.say("user-agent : ", headers["user-agent"], "<br/>")
  13. ngx.say("user-agent : ", headers.user_agent, "<br/>")
  14. for k,v in pairs(headers) do
  15. if type(v) == "table" then
  16. ngx.say(k, " : ", table.concat(v, ","), "<br/>")
  17. else
  18. ngx.say(k, " : ", v, "<br/>")
  19. end
  20. end
  21. ngx.say("headers end", "<br/>")
  22. ngx.say("<br/>")
  23. --get请求uri参数
  24. ngx.say("uri args begin", "<br/>")
  25. local uri_args = ngx.req.get_uri_args()
  26. for k, v in pairs(uri_args) do
  27. if type(v) == "table" then
  28. ngx.say(k, " : ", table.concat(v, ", "), "<br/>")
  29. else
  30. ngx.say(k, ": ", v, "<br/>")
  31. end
  32. end
  33. ngx.say("uri args end", "<br/>")
  34. ngx.say("<br/>")
  35. --post请求参数
  36. ngx.req.read_body()
  37. ngx.say("post args begin", "<br/>")
  38. local post_args = ngx.req.get_post_args()
  39. for k, v in pairs(post_args) do
  40. if type(v) == "table" then
  41. ngx.say(k, " : ", table.concat(v, ", "), "<br/>")
  42. else
  43. ngx.say(k, ": ", v, "<br/>")
  44. end
  45. end
  46. ngx.say("post args end", "<br/>")
  47. ngx.say("<br/>")
  48. --请求的http协议版本
  49. ngx.say("ngx.req.http_version : ", ngx.req.http_version(), "<br/>")
  50. --请求方法
  51. ngx.say("ngx.req.get_method : ", ngx.req.get_method(), "<br/>")
  52. --原始的请求头内容
  53. ngx.say("ngx.req.raw_header : ",  ngx.req.raw_header(), "<br/>")
  54. --请求的body内容体
  55. ngx.say("ngx.req.get_body_data() : ", ngx.req.get_body_data(), "<br/>")
  56. ngx.say("<br/>")

ngx.var : nginx变量,如果要赋值如ngx.var.b = 2,此变量必须提前声明;另外对于nginx location中使用正则捕获的捕获组可以使用ngx.var[捕获组数字]获取;

ngx.req.get_headers:获取请求头,默认只获取前100,如果想要获取所以可以调用ngx.req.get_headers(0);获取带中划线的请求头时请使用如headers.user_agent这种方式;如果一个请求头有多个值,则返回的是table;

ngx.req.get_uri_args:获取url请求参数,其用法和get_headers类似;

ngx.req.get_post_args:获取post请求内容体,其用法和get_headers类似,但是必须提前调用ngx.req.read_body()来读取body体(也可以选择在nginx配置文件使用lua_need_request_body on;开启读取body体,但是官方不推荐);

ngx.req.raw_header:未解析的请求头字符串;

ngx.req.get_body_data:为解析的请求body体内容字符串。

如上方法处理一般的请求基本够用了。另外在读取post内容体时根据实际情况设置client_body_buffer_sizeclient_max_body_size来保证内容在内存而不是在文件中。

使用如下脚本测试

Java代码  
  1. wget --post-data 'a=1&b=2' 'http://127.0.0.1/lua_request/1/2?a=3&b=4' -O -

输出响应

1.1、example.conf配置文件

Java代码  
  1. location /lua_response_1 {
  2. default_type "text/html";
  3. content_by_lua_file /usr/example/lua/test_response_1.lua;
  4. }

1.2、test_response_1.lua

Java代码  
  1. --写响应头
  2. ngx.header.a = "1"
  3. --多个响应头可以使用table
  4. ngx.header.b = {"2", "3"}
  5. --输出响应
  6. ngx.say("a", "b", "<br/>")
  7. ngx.print("c", "d", "<br/>")
  8. --200状态码退出
  9. return ngx.exit(200)

ngx.header:输出响应头;

ngx.print:输出响应内容体;

ngx.say:通ngx.print,但是会最后输出一个换行符;

ngx.exit:指定状态码退出。

2.1、example.conf配置文件

Java代码  
  1. location /lua_response_2 {
  2. default_type "text/html";
  3. content_by_lua_file /usr/example/lua/test_response_2.lua;
  4. }

2.2、test_response_2.lua

Java代码  
  1. ngx.redirect("http://jd.com", 302)

ngx.redirect:重定向;

ngx.status=状态码,设置响应的状态码;ngx.resp.get_headers()获取设置的响应状态码;ngx.send_headers()发送响应状态码,当调用ngx.say/ngx.print时自动发送响应状态码;可以通过ngx.headers_sent=true判断是否发送了响应状态码。

其他API

1、example.conf配置文件

Java代码  
  1. location /lua_other {
  2. default_type "text/html";
  3. content_by_lua_file /usr/example/lua/test_other.lua;
  4. }

2、test_other.lua

Java代码  
  1. --未经解码的请求uri
  2. local request_uri = ngx.var.request_uri;
  3. ngx.say("request_uri : ", request_uri, "<br/>");
  4. --解码
  5. ngx.say("decode request_uri : ", ngx.unescape_uri(request_uri), "<br/>");
  6. --MD5
  7. ngx.say("ngx.md5 : ", ngx.md5("123"), "<br/>")
  8. --http time
  9. ngx.say("ngx.http_time : ", ngx.http_time(ngx.time()), "<br/>")

ngx.escape_uri/ngx.unescape_uri : uri编码解码;

ngx.encode_args/ngx.decode_args:参数编码解码;

ngx.encode_base64/ngx.decode_base64:BASE64编码解码;

ngx.re.match:nginx正则表达式匹配;

更多Nginx Lua API请参考 http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua

Nginx全局内存

使用过如Java的朋友可能知道如Ehcache等这种进程内本地缓存,Nginx是一个Master进程多个Worker进程的工作方式,因此我们可能需要在多个Worker进程中共享数据,那么此时就可以使用ngx.shared.DICT来实现全局内存共享。

1、首先在nginx.conf的http部分分配内存大小

Java代码  
  1. #共享全局变量,在所有worker间共享
  2. lua_shared_dict shared_data 1m;

2、example.conf配置文件

Java代码  
  1. location /lua_shared_dict {
  2. default_type "text/html";
  3. content_by_lua_file /usr/example/lua/test_lua_shared_dict.lua;
  4. }

3、 test_lua_shared_dict.lua

Java代码  
  1. --1、获取全局共享内存变量
  2. local shared_data = ngx.shared.shared_data
  3. --2、获取字典值
  4. local i = shared_data:get("i")
  5. if not i then
  6. i = 1
  7. --3、惰性赋值
  8. shared_data:set("i", i)
  9. ngx.say("lazy set i ", i, "<br/>")
  10. end
  11. --递增
  12. i = shared_data:incr("i", 1)
  13. ngx.say("i=", i, "<br/>")

更多API请参考http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT

到此基本的Nginx Lua API就学完了,对于请求处理和输出响应如上介绍的API完全够用了,更多API请参考官方文档。

Nginx Lua模块指令

Nginx共11个处理阶段,而相应的处理阶段是可以做插入式处理,即可插拔式架构;另外指令可以在http、server、server if、location、location if几个范围进行配置:

指令

所处处理阶段

使用范围

解释

init_by_lua

init_by_lua_file

loading-config

http

nginx Master进程加载配置时执行;

通常用于初始化全局配置/预加载Lua模块

init_worker_by_lua

init_worker_by_lua_file

starting-worker

http

每个Nginx Worker进程启动时调用的计时器,如果Master进程不允许则只会在init_by_lua之后调用;

通常用于定时拉取配置/数据,或者后端服务的健康检查

set_by_lua

set_by_lua_file

rewrite

server,server if,location,location if

设置nginx变量,可以实现复杂的赋值逻辑;此处是阻塞的,Lua代码要做到非常快;

rewrite_by_lua

rewrite_by_lua_file

rewrite tail

http,server,location,location if

rrewrite阶段处理,可以实现复杂的转发/重定向逻辑;

access_by_lua

access_by_lua_file

access tail

http,server,location,location if

请求访问阶段处理,用于访问控制

content_by_lua

content_by_lua_file

content

location,location if

内容处理器,接收请求处理并输出响应

header_filter_by_lua

header_filter_by_lua_file

output-header-filter

http,server,location,location if

设置header和cookie

body_filter_by_lua

body_filter_by_lua_file

output-body-filter

http,server,location,location if

对响应数据进行过滤,比如截断、替换。

log_by_lua

log_by_lua_file

log

http,server,location,location if

log阶段处理,比如记录访问量/统计平均响应时间

更详细的解释请参考http://wiki.nginx.org/HttpLuaModule#Directives。如上指令很多并不常用,因此我们只拿其中的一部分做演示。

init_by_lua

每次Nginx重新加载配置时执行,可以用它来完成一些耗时模块的加载,或者初始化一些全局配置;在Master进程创建Worker进程时,此指令中加载的全局变量会进行Copy-OnWrite,即会复制到所有全局变量到Worker进程。

1、nginx.conf配置文件中的http部分添加如下代码

Java代码  
  1. #共享全局变量,在所有worker间共享
  2. lua_shared_dict shared_data 1m;
  3. init_by_lua_file /usr/example/lua/init.lua;

2、init.lua

Java代码  
  1. --初始化耗时的模块
  2. local redis = require 'resty.redis'
  3. local cjson = require 'cjson'
  4. --全局变量,不推荐
  5. count = 1
  6. --共享全局内存
  7. local shared_data = ngx.shared.shared_data
  8. shared_data:set("count", 1)

3、test.lua

Java代码  
  1. count = count + 1
  2. ngx.say("global variable : ", count)
  3. local shared_data = ngx.shared.shared_data
  4. ngx.say(", shared memory : ", shared_data:get("count"))
  5. shared_data:incr("count", 1)
  6. ngx.say("hello world")

4、访问如http://192.168.1.2/lua 会发现全局变量一直不变,而共享内存一直递增

global variable : 2 , shared memory : 8 hello world

另外注意一定在生产环境开启lua_code_cache,否则每个请求都会创建Lua VM实例。

init_worker_by_lua

用于启动一些定时任务,比如心跳检查,定时拉取服务器配置等等;此处的任务是跟Worker进程数量有关系的,比如有2个Worker进程那么就会启动两个完全一样的定时任务。

1、nginx.conf配置文件中的http部分添加如下代码

Java代码  
  1. init_worker_by_lua_file /usr/example/lua/init_worker.lua;

2、init_worker.lua

Java代码  
  1. local count = 0
  2. local delayInSeconds = 3
  3. local heartbeatCheck = nil
  4. heartbeatCheck = function(args)
  5. count = count + 1
  6. ngx.log(ngx.ERR, "do check ", count)
  7. local ok, err = ngx.timer.at(delayInSeconds, heartbeatCheck)
  8. if not ok then
  9. ngx.log(ngx.ERR, "failed to startup heartbeart worker...", err)
  10. end
  11. end
  12. heartbeatCheck()

ngx.timer.at:延时调用相应的回调方法;ngx.timer.at(秒单位延时,回调函数,回调函数的参数列表);可以将延时设置为0即得到一个立即执行的任务,任务不会在当前请求中执行不会阻塞当前请求,而是在一个轻量级线程中执行。

另外根据实际情况设置如下指令

lua_max_pending_timers 1024;  #最大等待任务数

lua_max_running_timers 256;    #最大同时运行任务数

set_by_lua 

设置nginx变量,我们用的set指令即使配合if指令也很难实现负责的赋值逻辑;

1.1、example.conf配置文件

Java代码  
  1. location /lua_set_1 {
  2. default_type "text/html";
  3. set_by_lua_file $num /usr/example/lua/test_set_1.lua;
  4. echo $num;
  5. }

set_by_lua_file:语法set_by_lua_file $var lua_file arg1 arg2...; 在lua代码中可以实现所有复杂的逻辑,但是要执行速度很快,不要阻塞;

1.2、test_set_1.lua

Java代码  
  1. local uri_args = ngx.req.get_uri_args()
  2. local i = uri_args["i"] or 0
  3. local j = uri_args["j"] or 0
  4. return i + j

得到请求参数进行相加然后返回。

访问如http://192.168.1.2/lua_set_1?i=1&j=10进行测试。 如果我们用纯set指令是无法实现的。

再举个实际例子,我们实际工作时经常涉及到网站改版,有时候需要新老并存,或者切一部分流量到新版

2.1、首先在example.conf中使用map指令来映射host到指定nginx变量,方便我们测试

Java代码  
  1. ############ 测试时使用的动态请求
  2. map $host $item_dynamic {
  3. default                     "0";
  4. item2014.jd.com            "1";
  5. }

如绑定hosts

192.168.1.2 item.jd.com;

192.168.1.2 item2014.jd.com;

此时我们想访问item2014.jd.com时访问新版,那么我们可以简单的使用如

Java代码  
  1. if ($item_dynamic = "1") {
  2. proxy_pass http://new;
  3. }
  4. proxy_pass http://old;

但是我们想把商品编号为为8位(比如品类为图书的)没有改版完成,需要按照相应规则跳转到老版,但是其他的到新版;虽然使用if指令能实现,但是比较麻烦,基本需要这样

Java代码  
  1. set jump "0";
  2. if($item_dynamic = "1") {
  3. set $jump "1";
  4. }
  5. if(uri ~ "^/6[0-9]{7}.html") {
  6. set $jump "${jump}2";
  7. }
  8. #非强制访问新版,且访问指定范围的商品
  9. if (jump == "02") {
  10. proxy_pass http://old;
  11. }
  12. proxy_pass http://new;

以上规则还是比较简单的,如果涉及到更复杂的多重if/else或嵌套if/else实现起来就更痛苦了,可能需要到后端去做了;此时我们就可以借助lua了:

Java代码  
  1. set_by_lua $to_book '
  2. local ngx_match = ngx.re.match
  3. local var = ngx.var
  4. local skuId = var.skuId
  5. local r = var.item_dynamic ~= "1" and ngx.re.match(skuId, "^[0-9]{8}$")
  6. if r then return "1" else return "0" end;
  7. ';
  8. set_by_lua $to_mvd '
  9. local ngx_match = ngx.re.match
  10. local var = ngx.var
  11. local skuId = var.skuId
  12. local r = var.item_dynamic ~= "1" and ngx.re.match(skuId, "^[0-9]{9}$")
  13. if r then return "1" else return "0" end;
  14. ';
  15. #自营图书
  16. if ($to_book) {
  17. proxy_pass http://127.0.0.1/old_book/$skuId.html;
  18. }
  19. #自营音像
  20. if ($to_mvd) {
  21. proxy_pass http://127.0.0.1/old_mvd/$skuId.html;
  22. }
  23. #默认
  24. proxy_pass http://127.0.0.1/proxy/$skuId.html;

rewrite_by_lua 

执行内部URL重写或者外部重定向,典型的如伪静态化的URL重写。其默认执行在rewrite处理阶段的最后。

1.1、example.conf配置文件

Java代码  
  1. location /lua_rewrite_1 {
  2. default_type "text/html";
  3. rewrite_by_lua_file /usr/example/lua/test_rewrite_1.lua;
  4. echo "no rewrite";
  5. }

1.2、test_rewrite_1.lua

Java代码  
  1. if ngx.req.get_uri_args()["jump"] == "1" then
  2. return ngx.redirect("http://www.jd.com?jump=1", 302)
  3. end

当我们请求http://192.168.1.2/lua_rewrite_1时发现没有跳转,而请求http://192.168.1.2/lua_rewrite_1?jump=1时发现跳转到京东首页了。 此处需要301/302跳转根据自己需求定义。

2.1、example.conf配置文件

Java代码  
  1. location /lua_rewrite_2 {
  2. default_type "text/html";
  3. rewrite_by_lua_file /usr/example/lua/test_rewrite_2.lua;
  4. echo "rewrite2 uri : $uri, a : $arg_a";
  5. }

2.2、test_rewrite_2.lua

Java代码  
  1. if ngx.req.get_uri_args()["jump"] == "1" then
  2. ngx.req.set_uri("/lua_rewrite_3", false);
  3. ngx.req.set_uri("/lua_rewrite_4", false);
  4. ngx.req.set_uri_args({a = 1, b = 2});
  5. end

ngx.req.set_uri(uri, false):可以内部重写uri(可以带参数),等价于 rewrite ^ /lua_rewrite_3;通过配合if/else可以实现 rewrite ^ /lua_rewrite_3 break;这种功能;此处两者都是location内部url重写,不会重新发起新的location匹配;

ngx.req.set_uri_args:重写请求参数,可以是字符串(a=1&b=2)也可以是table;

访问如http://192.168.1.2/lua_rewrite_2?jump=0时得到响应

rewrite2 uri : /lua_rewrite_2, a :

访问如http://192.168.1.2/lua_rewrite_2?jump=1时得到响应

rewrite2 uri : /lua_rewrite_4, a : 1

3.1、example.conf配置文件

Java代码  
  1. location /lua_rewrite_3 {
  2. default_type "text/html";
  3. rewrite_by_lua_file /usr/example/lua/test_rewrite_3.lua;
  4. echo "rewrite3 uri : $uri";
  5. }

3.2、test_rewrite_3.lua

Java代码  
  1. if ngx.req.get_uri_args()["jump"] == "1" then
  2. ngx.req.set_uri("/lua_rewrite_4", true);
  3. ngx.log(ngx.ERR, "=========")
  4. ngx.req.set_uri_args({a = 1, b = 2});
  5. end

ngx.req.set_uri(uri, true):可以内部重写uri,即会发起新的匹配location请求,等价于 rewrite ^ /lua_rewrite_4 last;此处看error log是看不到我们记录的log。

所以请求如http://192.168.1.2/lua_rewrite_3?jump=1会到新的location中得到响应,此处没有/lua_rewrite_4,所以匹配到/lua请求,得到类似如下的响应

global variable : 2 , shared memory : 1 hello world

rewrite ^ /lua_rewrite_3;                 等价于  ngx.req.set_uri("/lua_rewrite_3", false);

rewrite ^ /lua_rewrite_3 break;       等价于  ngx.req.set_uri("/lua_rewrite_3", false); 加 if/else判断/break/return

rewrite ^ /lua_rewrite_4 last;           等价于  ngx.req.set_uri("/lua_rewrite_4", true);

注意,在使用rewrite_by_lua时,开启rewrite_log on;后也看不到相应的rewrite log。

access_by_lua 

用于访问控制,比如我们只允许内网ip访问,可以使用如下形式

Java代码  
  1. allow     127.0.0.1;
  2. allow     10.0.0.0/8;
  3. allow     192.168.0.0/16;
  4. allow     172.16.0.0/12;
  5. deny      all;

1.1、example.conf配置文件

Java代码  
  1. location /lua_access {
  2. default_type "text/html";
  3. access_by_lua_file /usr/example/lua/test_access.lua;
  4. echo "access";
  5. }

1.2、test_access.lua

Java代码  
  1. if ngx.req.get_uri_args()["token"] ~= "123" then
  2. return ngx.exit(403)
  3. end

即如果访问如http://192.168.1.2/lua_access?token=234将得到403 Forbidden的响应。这样我们可以根据如cookie/用户token来决定是否有访问权限。

content_by_lua 

此指令之前已经用过了,此处就不讲解了。

另外在使用PCRE进行正则匹配时需要注意正则的写法,具体规则请参考http://wiki.nginx.org/HttpLuaModule中的Special PCRE Sequences部分。还有其他的注意事项也请阅读官方文档。

nginx 与 lua 开发笔记的更多相关文章

  1. nginx 与 lua 开发环境搭建

    首先下载最新版的 相关软件 的安装文件. nginx: http://nginx.org/en/download.html LuaJIT: http://luajit.org/download.htm ...

  2. Nginx与Lua开发

    1.Lua及基础语法 Nginx与Lua环境 场景:用Nginx结合Lua实现代码的灰度发布 1.Lua 是一个简洁.轻量.可扩展的脚本语言 2.Nginx+Lua优势 充分的结合Nginx的并发处理 ...

  3. nginx lua 开发笔记

    获取 在lua代码中获取 location 正则的参数对应的变量 // location location ~/lua_http_2/(\w*.+) { } // lua local vars=ngx ...

  4. Nginx与Lua的开发

    1. Lua基础语法 安装lua hello world 也可以编写lua脚本 运行脚本 lua注释 变量 局部变量的话前面加个local 循环 if语句 2. Nginx与Lua开发环境 https ...

  5. (转)OpenResty(nginx+lua) 开发入门

    原文:https://blog.csdn.net/enweitech/article/details/78519398 OpenResty 官网:http://openresty.org/  Open ...

  6. 【精选】Nginx模块Lua-Nginx-Module学习笔记(二)Lua指令详解(Directives)

    源码地址:https://github.com/Tinywan/Lua-Nginx-Redis Nginx与Lua编写脚本的基本构建块是指令. 指令用于指定何时运行用户Lua代码以及如何使用结果. 下 ...

  7. Nginx详解二十三:Nginx深度学习篇之Nginx+Lua开发环境搭建

    Nginx+Lua开发环境 1.下载LuaJIT解释器wget http://luajit.org/download/LuaJIT-2.0.2.tar.gztar -zxvf LuaJIT-2.0.2 ...

  8. CentOS安装OpenResty(Nginx+Lua)开发环境

    一.简介 OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库.第三方模块以及大多数的依赖项.用于方便地搭建能够处理超高并发.扩展性极高 ...

  9. (转)Lua学习笔记1:Windows7下使用VS2015搭建Lua开发环境

    Lua学习笔记1:Windows7下使用VS2015搭建Lua开发环境(一)注意:工程必须添加两个宏:“配置属性”/“C或C++”/“预处理器”/“预处理器定义”,添加两个宏:_CRT_SECURE_ ...

随机推荐

  1. 设计模式之代理模式(php实现)

    github地址:https://github.com/ZQCard/design_pattern /** * 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口. * 1.Window ...

  2. java 中 HashMap 遍历与删除

    HashMap的遍历 方法一.这是最常见的并且在大多数情况下也是最可取的遍历方式 /** * 在键值都需要时使用 */ Map<Integer, Integer> map = new Ha ...

  3. java - day11 - OverRideTest

    概念 1.重写:看调用方法的对象:如果调用的是子类对象,则无论父类/子类引用类型,调用的都是重写后的方法,如果想调用父类的方法,用super.方法 来调:如果调用的是父类对象,则调用的是父类重写前的方 ...

  4. java代码中fastjson生成字符串和解析字符串的方法和javascript文件中字符串和json数组之间的转换方法

    1.java代码中fastjson生成字符串和解析字符串的方法 List<TemplateFull> templateFulls = new ArrayList<TemplateFu ...

  5. SQL中使用视图的优点和缺点是什么

    视图的优点与缺点 在程序设计的时候必须先了解视图的优缺点,这样可以扬长避短,视图具有如下的一些优点: ● 简单性.视图不仅可以简化用户对数据的理解,也可以简化他们的操作.那些被经常使用的查询可以被定义 ...

  6. int和Integer差别

    种原始数据类型之中的一个. Java为每一个原始类型提供了封装类.Integer是java为int提供的封装类. 原始数据类型包含byte.int.char.long.float.double.boo ...

  7. 配置Redmine的邮件通知功能

    依据<Windows下安装Redmine 2.5.2不全然指南 >一文,我们搭建主要的 Redmine 平台.如今是时候做进一步的配置了. 作为一个项目管理平台,必须能够通知项目成员有关项 ...

  8. Redis的Aof被阻塞原因调查

    背景 Redis是单进程的,为了发挥多核的优势,我们redis集群采用在单台机器上部署多个redis实例,同时对持久化方式做了改进,采用rdb和增量的aof相结合的方式,appendfsync配置为n ...

  9. Web Services 概要

    WSDL WSDL 是基于 XML 的用来描述 Web services 以及如何访问它们的一种语言. WSDL 可描述 web service,连同用于 web service 的消息格式和协议的细 ...

  10. JavaScript 框架(库)

    JavaScript 高级程序设计(特别是对浏览器差异的复杂处理),通常很困难也很耗时. 为了应对这些调整,许多的 JavaScript (helper) 库应运而生. 这些 JavaScript 库 ...