欢迎来到淼淼之森的个人小站。  交流请加我微信好友: studyjava。  也欢迎关注同名公众号:Java学习之道

整理开发中遇到的所有问题之后台(持续整理中) 置顶!

  |   0 评论   |   0 浏览

Java

Spring

SpringMVC

  • HandlerInterceptorAdapter
  • HandlerInterceptor

SpringBoot

swagger

SpringBoot整合swagger2的时候,一直弹窗的问题。

原因是swagger2的静态资源文件被SpringBoot拦截器给拦截了,导致一直访问不到具体的页面。解决方案:

  • 在application.yml里面配置
include-urls: ["/**"] #拦截所有请求
exclude-urls: ["/v2/api-docs", "/swagger-ui.html", "/webjars/**", "/swagger-resources/**",
"/web/**", "/static/**"] #不需要拦截的请求
  • 在拦截器里面配置
String servletPath = request.getServletPath();
    // 加载需要转换的URL
    if (includeUrls != null) {
        for (String pattern : includeUrls) {
            if (PATH_MATCHER.match(pattern, servletPath)) {
                convertMessage = true;
            }
        }
    }
    // 排除不需要转换的URL
    if (excludeUrls != null) {
        for (String pattern : excludeUrls) {
            if (PATH_MATCHER.match(pattern, servletPath)) {
                convertMessage = false;
            }
        }
    }

    // 不需要转换
    if (convertMessage == null || !convertMessage || !JSON_MEDIA_TYPE.contains(mediaType) || object instanceof MicroMetaData) {
        return object;
    }

拦截器的问题

在spring boot 2.0项目中写拦截器时,遇到一个小问题,记录一下。错误日志如下

java.lang.ClassCastException: org.springframework.web.servlet.resource.ResourceHttpRequestHandler cannot be cast to org.springframework.web.method.HandlerMethod

拦截器中部分代码如下

public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
            //此处报错
            HandlerMethod handlerMethod = (HandlerMethod) handler;
}

原因是:spring boot 2.0对静态资源也进行了拦截,当拦截器拦截到请求之后,但controller里并没有对应的请求时,该请求会被当成是对静态资源的请求。此时的handler就是 ResourceHttpRequestHandler,就会抛出上述错误。
解决方法:在拦截器那里排除静态资源的请求路径。

registry.addInterceptor(new JJRUserLoginInterceptor()).addPathPatterns("/xx/**")
                .excludePathPatterns("/xx/**");

然后在报错那里加上 instanceof关键字进行判断。

获取项目根目录

//获取根目录
File path = new File(ResourceUtils.getURL("classpath:").getPath());
if(!path.exists()) path = new File("");
System.out.println("path:"+path.getAbsolutePath());

//如果上传目录为/static/images/upload/,则可以如下获取:
File upload = new File(path.getAbsolutePath(),"static/images/upload/");
if(!upload.exists()) upload.mkdirs();
System.out.println("upload url:"+upload.getAbsolutePath());
//在开发测试模式时,得到的地址为:{项目跟目录}/target/static/images/upload/
//在打包成jar正式发布时,得到的地址为:{发布jar包目录}/static/images/upload/

SpringBoot设置文件上传限制

使用SpringBoot2.0.3的版本,会发现如下设置过期

spring.http.multipart.maxFileSize=10Mb  
spring.http.multipart.maxRequestSize=10Mb

无意间打开spring-configuration-metadata.json文件,发现如下内容:

 {
      "defaultValue": "1MB",
      "deprecated": true,
      "name": "spring.http.multipart.max-file-size",
      "description": "Max file size. Values can use the suffixes \"MB\" or \"KB\" to indicate megabytes or\n kilobytes respectively.",
      "type": "java.lang.String",
      "deprecation": {
        "level": "error",
        "replacement": "spring.servlet.multipart.max-file-size"
      }
    },
    {
      "defaultValue": "10MB",
      "deprecated": true,
      "name": "spring.http.multipart.max-request-size",
      "description": "Max request size. Values can use the suffixes \"MB\" or \"KB\" to indicate megabytes or\n kilobytes respectively.",
      "type": "java.lang.String",
      "deprecation": {
        "level": "error",
        "replacement": "spring.servlet.multipart.max-request-size"
      }
    },

由此可以看到,设置改为了

spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

Thymeleaf

字符串Strings常见的使用方法
判断是不是为空:null: 
<span th:if="${name} != null">不为空</span> 
<span th:if="${name1} == null">为空</span> 
判断是不是为空字符串: “” 
<span th:if="${#strings.isEmpty(name1)}">空的</span> 
判断是否相同: 
<span th:if="${name} eq 'jack'">相同于jack,</span> 
<span th:if="${name} eq 'ywj'">相同于ywj,</span> 
<span th:if="${name} ne 'jack'">不相同于jack,</span> 
不存在设置默认值: 
<span th:text="${name2} ?: '默认值'"></span> 
是否包含(分大小写): 
<span th:if="${#strings.contains(name,'ez')}">包ez</span> 
<span th:if="${#strings.contains(name,'y')}">包j</span> 
是否包含(不分大小写) 
<span th:if="${#strings.containsIgnoreCase(name,'y')}">包j</span> 
同理。。。下面的和JAVA的String基本一样。。。。不笔记解释,官网有

${#strings.startsWith(name,'o')} 
${#strings.endsWith(name, 'o')} 
${#strings.indexOf(name,frag)}// 下标 
${#strings.substring(name,3,5)}// 截取 
${#strings.substringAfter(name,prefix)}// 从 prefix之后的一位开始截取到最后,比如 (ywj,y) = wj, 如果是(abccdefg,c) = cdefg//里面有2个c,取的是第一个c 
${#strings.substringBefore(name,suffix)}// 同上,不过是往前截取 
${#strings.replace(name,'las','ler')}// 替换 
${#strings.prepend(str,prefix)}// 拼字字符串在str前面 
${#strings.append(str,suffix)}// 和上面相反,接在后面 
${#strings.toUpperCase(name)} 
${#strings.toLowerCase(name)} 
${#strings.trim(str)} 
${#strings.length(str)} 
${#strings.abbreviate(str,10)}// 我的理解是 str截取0-10位,后面的全部用…这个点代替,注意,最小是3位
Thymeleaf 条件判断
gt:great than(大于)>
ge:great equal(大于等于)>=
eq:equal(等于)==
lt:less than(小于)<
le:less equal(小于等于)<=
ne:not equal(不等于)!=
这里以th:if为例,其他差不多

用法:

例:th:if="${xx} lt 'x'"  <-----------> xx < x  
<div th:if=" ${userCarSize} lt '3'">
  <div class="addList">
    <p>
       <a id="gotobindView">
            <span class="icon"></span>添加绑定
        </a>
    </p>
   <p>最多绑定三辆车</p>
    </div>
</div>
Thymeleaf switch case
<div th:switch="${user.role}">
  <p th:case="'admin'">User is an administrator</p>
  <p th:case="#{roles.manager}">User is a manager</p>
  <p th:case="*">User is some other thing</p>
</div>
th:case = "*" 表示默认,与default类似。   

velocity模板引擎(类似Java语法)

基本用法
$!{value} # 如果值不存在,则为空
${value} # 如果值不存在,则原样显示,不解析。
#foreach(${value} in ${list})#遍历以value命名每个变量遍历list
    ${value}
#end
$!{foreach.index} # 遍历的索引
$!{foreach.count} # 遍历的数量(第几个)
#foreach($key in $map.keySet()) # 循环遍历map
    $key,$map.get($key)
#end
#set($title='test') #自定义变量
$!{title}
#parse("header.html")#引入文件,会解析变量。
#include("header.html") #引入文件,但是不会解析文件中的变量。
#macro(render_color,$index,$color)
    Color Render Macro $index,$color
#end

Spring Test

java.lang.IllegalStateException: Could not load TestContextBootstrapper [null]. Specify @BootstrapWi

在使用spring-test插件执行单元测试时,需要注意的是spring-webmvc的版本应该与spring-test的版本一致,否则在执行junit测试时就会出现“java.lang.IllegalStateException: Could not load TestContextBootstrapper [null]. Specify @BootstrapWith's 'value' attribute or make the default bootstrapper class available.”这个异常

日志框架

log4j.properties

################################################################################ 
#配置根Logger,其语法为: 
# 
#log4j.rootLogger = [level],appenderName,appenderName2,... 
#level是日志记录的优先级,分为OFF,TRACE,DEBUG,INFO,WARN,ERROR,FATAL,ALL 
##Log4j建议只使用四个级别,优先级从低到高分别是DEBUG,INFO,WARN,ERROR 
#通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关 
#比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来 
#appenderName就是指定日志信息输出到哪个地方。可同时指定多个输出目的 
################################################################################ 
################################################################################ 
#配置日志信息输出目的地Appender,其语法为: 
# 
#log4j.appender.appenderName = fully.qualified.name.of.appender.class 
#log4j.appender.appenderName.optionN = valueN 
# 
#Log4j提供的appender有以下几种: 
#1)org.apache.log4j.ConsoleAppender(输出到控制台) 
#2)org.apache.log4j.FileAppender(输出到文件) 
#3)org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件) 
#4)org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件) 
#5)org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方) 
# 
#1)ConsoleAppender选项属性 
# -Threshold = DEBUG:指定日志消息的输出最低层次 
# -ImmediateFlush = TRUE:默认值是true,所有的消息都会被立即输出 
# -Target = System.err:默认值System.out,输出到控制台(err为红色,out为黑色) 
# 
#2)FileAppender选项属性 
# -Threshold = INFO:指定日志消息的输出最低层次 
# -ImmediateFlush = TRUE:默认值是true,所有的消息都会被立即输出 
# -File = C:\log4j.log:指定消息输出到C:\log4j.log文件 
# -Append = FALSE:默认值true,将消息追加到指定文件中,false指将消息覆盖指定的文件内容 
# -Encoding = UTF-8:可以指定文件编码格式 
# 
#3)DailyRollingFileAppender选项属性 
# -Threshold = WARN:指定日志消息的输出最低层次 
# -ImmediateFlush = TRUE:默认值是true,所有的消息都会被立即输出 
# -File = C:\log4j.log:指定消息输出到C:\log4j.log文件 
# -Append = FALSE:默认值true,将消息追加到指定文件中,false指将消息覆盖指定的文件内容 
# -DatePattern='.'yyyy-ww:每周滚动一次文件,即每周产生一个新的文件。还可以按用以下参数: 
#              '.'yyyy-MM:每月 
#              '.'yyyy-ww:每周 
#              '.'yyyy-MM-dd:每天 
#              '.'yyyy-MM-dd-a:每天两次 
#              '.'yyyy-MM-dd-HH:每小时 
#              '.'yyyy-MM-dd-HH-mm:每分钟 
# -Encoding = UTF-8:可以指定文件编码格式 
# 
#4)RollingFileAppender选项属性 
# -Threshold = ERROR:指定日志消息的输出最低层次 
# -ImmediateFlush = TRUE:默认值是true,所有的消息都会被立即输出 
# -File = C:/log4j.log:指定消息输出到C:/log4j.log文件 
# -Append = FALSE:默认值true,将消息追加到指定文件中,false指将消息覆盖指定的文件内容 
# -MaxFileSize = 100KB:后缀可以是KB,MB,GB.在日志文件到达该大小时,将会自动滚动.如:log4j.log.1 
# -MaxBackupIndex = 2:指定可以产生的滚动文件的最大数 
# -Encoding = UTF-8:可以指定文件编码格式 
################################################################################ 
################################################################################ 
#配置日志信息的格式(布局),其语法为: 
# 
#log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class 
#log4j.appender.appenderName.layout.optionN = valueN 
# 
#Log4j提供的layout有以下几种: 
#5)org.apache.log4j.HTMLLayout(以HTML表格形式布局) 
#6)org.apache.log4j.PatternLayout(可以灵活地指定布局模式) 
#7)org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串) 
#8)org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息) 
#9)org.apache.log4j.xml.XMLLayout(以XML形式布局) 
# 
#5)HTMLLayout选项属性 
# -LocationInfo = TRUE:默认值false,输出java文件名称和行号 
# -Title=Struts Log Message:默认值 Log4J Log Messages 
# 
#6)PatternLayout选项属性 
# -ConversionPattern = %m%n:格式化指定的消息(参数意思下面有) 
# 
#9)XMLLayout选项属性 
# -LocationInfo = TRUE:默认值false,输出java文件名称和行号 
# 
#Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下: 
# %m 输出代码中指定的消息 
# %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL 
# %r 输出自应用启动到输出该log信息耗费的毫秒数 
# %c 输出所属的类目,通常就是所在类的全名 
# %t 输出产生该日志事件的线程名 
# %n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n” 
# %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式 
#    如:%d{yyyy年MM月dd日 HH:mm:ss,SSS},输出类似:2012年01月05日 22:10:28,921 
# %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数 
#    如:Testlog.main(TestLog.java:10) 
# %F 输出日志消息产生时所在的文件名称 
# %L 输出代码中的行号 
# %x 输出和当前线程相关联的NDC(嵌套诊断环境),像java servlets多客户多线程的应用中 
# %% 输出一个"%"字符 
# 
# 可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如: 
#  %5c: 输出category名称,最小宽度是5,category<5,默认的情况下右对齐 
#  %-5c:输出category名称,最小宽度是5,category<5,"-"号指定左对齐,会有空格 
#  %.5c:输出category名称,最大宽度是5,category>5,就会将左边多出的字符截掉,<5不会有空格 
#  %20.30c:category名称<20补空格,并且右对齐,>30字符,就从左边交远销出的字符截掉 
################################################################################ 
################################################################################ 
#指定特定包的输出特定的级别 
#log4j.logger.org.springframework=DEBUG 
################################################################################ 

#OFF,systemOut,logFile,logDailyFile,logRollingFile,logMail,logDB,ALL 
log4j.rootLogger =ALL,systemOut,logFile,logDailyFile,logRollingFile,logMail,logDB 

#输出到控制台 
log4j.appender.systemOut = org.apache.log4j.ConsoleAppender 
log4j.appender.systemOut.layout = org.apache.log4j.PatternLayout 
log4j.appender.systemOut.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n 
log4j.appender.systemOut.Threshold = DEBUG 
log4j.appender.systemOut.ImmediateFlush = TRUE 
log4j.appender.systemOut.Target = System.out 

#输出到文件 
log4j.appender.logFile = org.apache.log4j.FileAppender 
log4j.appender.logFile.layout = org.apache.log4j.PatternLayout 
log4j.appender.logFile.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n 
log4j.appender.logFile.Threshold = DEBUG 
log4j.appender.logFile.ImmediateFlush = TRUE 
log4j.appender.logFile.Append = TRUE 
log4j.appender.logFile.File = ../Struts2/WebRoot/log/File/log4j_Struts.log 
log4j.appender.logFile.Encoding = UTF-8 

#按DatePattern输出到文件 
log4j.appender.logDailyFile = org.apache.log4j.DailyRollingFileAppender 
log4j.appender.logDailyFile.layout = org.apache.log4j.PatternLayout 
log4j.appender.logDailyFile.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n 
log4j.appender.logDailyFile.Threshold = DEBUG 
log4j.appender.logDailyFile.ImmediateFlush = TRUE 
log4j.appender.logDailyFile.Append = TRUE 
log4j.appender.logDailyFile.File = ../Struts2/WebRoot/log/DailyFile/log4j_Struts 
log4j.appender.logDailyFile.DatePattern = '.'yyyy-MM-dd-HH-mm'.log' 
log4j.appender.logDailyFile.Encoding = UTF-8 

#设定文件大小输出到文件 
log4j.appender.logRollingFile = org.apache.log4j.RollingFileAppender 
log4j.appender.logRollingFile.layout = org.apache.log4j.PatternLayout 
log4j.appender.logRollingFile.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n 
log4j.appender.logRollingFile.Threshold = DEBUG 
log4j.appender.logRollingFile.ImmediateFlush = TRUE 
log4j.appender.logRollingFile.Append = TRUE 
log4j.appender.logRollingFile.File = ../Struts2/WebRoot/log/RollingFile/log4j_Struts.log 
log4j.appender.logRollingFile.MaxFileSize = 1MB 
log4j.appender.logRollingFile.MaxBackupIndex = 10 
log4j.appender.logRollingFile.Encoding = UTF-8 

#用Email发送日志 
log4j.appender.logMail = org.apache.log4j.net.SMTPAppender 
log4j.appender.logMail.layout = org.apache.log4j.HTMLLayout 
log4j.appender.logMail.layout.LocationInfo = TRUE 
log4j.appender.logMail.layout.Title = Struts2 Mail LogFile 
log4j.appender.logMail.Threshold = DEBUG 
log4j.appender.logMail.SMTPDebug = FALSE 
log4j.appender.logMail.SMTPHost = SMTP.163.com 
log4j.appender.logMail.From = xly3000@163.com 
log4j.appender.logMail.To = xly3000@gmail.com 
#log4j.appender.logMail.Cc = xly3000@gmail.com 
#log4j.appender.logMail.Bcc = xly3000@gmail.com 
log4j.appender.logMail.SMTPUsername = xly3000 
log4j.appender.logMail.SMTPPassword = 1234567 
log4j.appender.logMail.Subject = Log4j Log Messages 
#log4j.appender.logMail.BufferSize = 1024 
#log4j.appender.logMail.SMTPAuth = TRUE 

#将日志登录到MySQL数据库 
log4j.appender.logDB = org.apache.log4j.jdbc.JDBCAppender 
log4j.appender.logDB.layout = org.apache.log4j.PatternLayout 
log4j.appender.logDB.Driver = com.mysql.jdbc.Driver 
log4j.appender.logDB.URL = jdbc:mysql://127.0.0.1:3306/xly 
log4j.appender.logDB.User = root 
log4j.appender.logDB.Password = 123456 
log4j.appender.logDB.Sql = INSERT INTOT_log4j(project_name,create_date,level,category,file_name,thread_name,line,all_category,message)values('Struts2','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')

Oracle

Oracle列转行

SELECT ROWNUM, AREA_NAME,OLD_TOTAL,NEW_TOTAL,OLD_TOTAL+NEW_TOTAL AS TOTAL FROM 
(
SELECT  
SUM(CASE WHEN CITY_AREA_YEAR < '2018' THEN WUHOU*TOTAL_ACCOUNT END) a, 
SUM(CASE WHEN CITY_AREA_YEAR = '2018' THEN WUHOU*TOTAL_ACCOUNT END) a2, 
SUM(CASE WHEN CITY_AREA_YEAR < '2018' THEN CHENGHUA*TOTAL_ACCOUNT END) b,
SUM(CASE WHEN CITY_AREA_YEAR = '2018' THEN CHENGHUA*TOTAL_ACCOUNT END) b2,
SUM(CASE WHEN CITY_AREA_YEAR < '2018' THEN QINGYANG*TOTAL_ACCOUNT END) c,
SUM(CASE WHEN CITY_AREA_YEAR = '2018' THEN QINGYANG*TOTAL_ACCOUNT END) c2,
SUM(CASE WHEN CITY_AREA_YEAR < '2018' THEN JINNIU*TOTAL_ACCOUNT END) d,
SUM(CASE WHEN CITY_AREA_YEAR = '2018' THEN JINNIU*TOTAL_ACCOUNT END) d2,
SUM(CASE WHEN CITY_AREA_YEAR < '2018' THEN JINJIANG*TOTAL_ACCOUNT END) e,
SUM(CASE WHEN CITY_AREA_YEAR = '2018' THEN JINJIANG*TOTAL_ACCOUNT END) e2,
SUM(CASE WHEN CITY_AREA_YEAR < '2018' THEN GAOXIN*TOTAL_ACCOUNT END) f,
SUM(CASE WHEN CITY_AREA_YEAR = '2018' THEN GAOXIN*TOTAL_ACCOUNT END) f2,
SUM(CASE WHEN CITY_AREA_YEAR < '2018' THEN TOTAL_ACCOUNT END) t,
SUM(CASE WHEN CITY_AREA_YEAR = '2018' THEN TOTAL_ACCOUNT END) t2
FROM CITY_AREA_TOTAL
)T
UNPIVOT 
(
(OLD_TOTAL,NEW_TOTAL) FOR AREA_NAME IN
(
(a,a2) AS '武侯区',
(b,b2) AS '成华区',
(c,c2) AS '青羊区',
(d,d2) AS '金牛区',
(e,e2) AS '锦江区',
(f,f2) AS '高新区',
(t,t2) AS '合计'
)
)

nginx

nginx.conf文件结构

#全局块

events {         #events块
   ...
}

http      #http块
{
...   #http全局块
server        #server块
{ 
...       #server全局块
location [PATTERN]   #location块
{
...
}
location [PATTERN] 
{
...
}
}
server
{
  ...
}
...     #http全局块
}
匹配规则:
例:
http {
upstream ht { 
  server 127.0.0.1:8080 weight=1;  
  server 127.0.0.1:8081 weight=2; 
}
    server {
        listen       80;
        server_name  localhost;

        location / {
            root   html;
            proxy_pass http://ht;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
}
}

全局块

配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。

events块

配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。

http块

可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。

server块

配置虚拟主机的相关参数,一个http中可以有多个server。

location块

配置请求的路由,以及各种页面的处理情况。

示例1

########### 每个指令必须有分号结束。#################
#user administrator administrators;  #配置用户或者组,默认为nobody nobody。
#worker_processes 2;  #允许生成的进程数,默认为1
#pid /nginx/pid/nginx.pid;   #指定nginx进程运行文件存放地址
error_log log/error.log debug;  #制定日志路径,级别。这个设置可以放入全局块,http块,server块,级别以此为:debug|info|notice|warn|error|crit|alert|emerg
events {
accept_mutex on;   #设置网路连接序列化,防止惊群现象发生,默认为on
multi_accept on;  #设置一个进程是否同时接受多个网络连接,默认为off
#use epoll;      #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
worker_connections  1024;    #最大连接数,默认为512
}
http {
include       mime.types;   #文件扩展名与文件类型映射表
default_type  application/octet-stream; #默认文件类型,默认为text/plain
#access_log off; #取消服务日志    
log_format myFormat '$remote_addr–$remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for'; #自定义格式
access_log log/access.log myFormat;  #combined为日志格式的默认值
sendfile on;   #允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。
sendfile_max_chunk 100k;  #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。
keepalive_timeout 65;  #连接超时时间,默认为75s,可以在http,server,location块。

upstream mysvr {   
  server 127.0.0.1:7878;
  server 192.168.10.121:3333 backup;  #热备
}
error_page 404 https://www.baidu.com; #错误页
server {
keepalive_requests 120; #单连接请求上限次数。
listen       4545;   #监听端口
server_name  127.0.0.1;   #监听地址       
location  ~*^.+$ {       #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
   #root path;  #根目录
   #index vv.txt;  #设置默认页
   proxy_pass  http://mysvr;  #请求转向mysvr 定义的服务器列表
   deny 127.0.0.1;  #拒绝的ip
   allow 172.18.5.54; #允许的ip           
} 
}
} 

示例2

http://localhost:80/my_project/xxx.jsp
-> 第一个http 进入http模块
-> 第二个localhost表示server则进入server模块,即ip地址或服务器别名匹配server_name属性
-> 第三个匹配端口号,则匹配listen监听的端口号。如上配置。
-> 而具体最后的路径,则进入location所指定的正则进行匹配。如果是/则表示根目录下所有的都要进入到此逻辑进行处理。
-> 指定的proxy_pass 则是用来转发到具体的某个服务器进行处理,如http://ht
则会使用upstream名为ht的进行执行,并根据相应的权重|ip_hash|轮询等方式进行处理,这里就是nginx的负载均衡。
-> 如果没有匹配到任何页面或者资源,则会进入location = /50x.html进行处理,这里的 = 则表示精准匹配。

Tomcat

部署项目时的一些问题

# 指定项目位置,Tomcat会根据指定位置将项目加载至webapps下(如果path设置为/,则会创建一个ROOT的根目录存放项目):
<Context path="/"
   docBase="/opt/web/tomcat7/tft"
   crossContext="true"
   debug="0"
   reloadable="true"
   trusted="false" >
</Context>
# 如果想要加载多个项目,则指定path为对应的项目名:
<Context path="/project1"
   docBase="/opt/web/tomcat7/tft/project1.war"  crossContext="true"
   debug="0"
   reloadable="true"
   trusted="false" >
</Context>
<Context path="/project2"
   docBase="/opt/web/tomcat7/tft/project2.war"  crossContext="true"
   debug="0"
   reloadable="true"
   trusted="false">
</Context>

使用redis解决tomcat的session共享的问题

1、安装redis

2、配置tomcat的context.xml

在<Context>下添加:
<Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve" />
<Manager className="com.radiadesign.catalina.session.RedisSessionManager"
   host="10.50.7.31"
   port="6379"
   database="0"
   maxInactiveInterval="60"
   password="huatengckapp"
/>

3、添加lib中的依赖包

jedis-2.2.1.jar commons-pool-1.6.jar
commons-pool2-2.2.jar
tomcat-redis-session-manager-1.2-tomcat-7-java-7.jar

注意:版本问题。

4、启动tomcat

Maven

强制安装xxxx.jar

# 以ojdbcx.jar为例:
mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc14 -Dversion=10.2.0.1.0 -Dpackaging=jar -Dfile=D:\ojdbc14.jar

解决jar包冲突(omitted for duplicate)

mvn dependency:tree -Dverbose //显示项目依赖树
mvn dependency:analyze  //查看项目依赖
mvn dependency:tree   //查看项目直接和传递依赖
mvn help:effective-pom  //查看maven构建时有效的pom

来看哪些jar是不需要的,再排除就好了。

Maven打包时,无法打包sun公司的私有包的问题

代码里引用sun公司私有的类,而maven打包的时候,默认是不会把rt.jar等包打包进去,所以才会出现编译不通过的问题。解决办法:

  •  不要使用sun的私有类,改用开源的一些来代替
  •  强制在编译时把这个包导入(但配置的参数一定要通用化,不要出现盘符和jdk版本名称等,最好用相对位置)

爬虫

selenium api

浏览器操作

# 刷新
driver.refresh()
 
# 前进
driver.forward()
 
# 后退
driver.back()

获取标签元素

# 通过ID定位目标元素
driver.find_element_by_id('i1')
 
# 通过className定位目标元素
driver.find_element_by_class_name('c1')
 
# 通过name属性定位目标元素
driver.find_element_by_name('n1')
 
# 通过Xpath定位目标元素
driver.find_element_by_xpath('//*[@id="i1"]')
 
# 通过css Selector定位目标元素
driver.find_element_by_css_selector('#i1')
 
# 通过标签名称定位(注:在一个页面中,标签一定会重复,所以不用这个来进行定位)
driver.find_element_by_tag_name('input')
 
# 通过标签中的文本查找元素
driver.find_element_by_link_text('登录')
 
# 通过标签中文本的模糊匹配查找
driver.find_elements_by_partial_link_text('录')

获取标签元素常用的一共有8种定位方式,而Selenium实际提供了18种定位方式,还有8种是上面的复数形式,这里就不一一介绍了,实际运用中并不常用,还有2种实际上是这上面所说16种的底层封装。参数化的一种调用方式而已。

  • Cookie操作
# 根据cookieKey,获取cookie信息
cookie = driver.get_cookie('cookieKey')
 
# 获取所有cookie信息
cookies = driver.get_cookies()
 
# 添加cookie,严格按照格式添加,cookie的key为name,value为value
driver.add_cookie({'name':'tmp','value':'123123123'})
 
# 删除所有cookie信息
driver.delete_all_cookies()
 
# 根据cookieKey删除对应cookie
driver.delete_cookie('UiCode')

窗口操作

# 获取当前浏览器的大小
driver.get_window_size()
 
# 通过像素设置浏览器的大小
driver.set_window_size('width','height')
 
# 获取当前窗口针对于Windows的位置的坐标x,y
driver.get_window_position()
 
# 设置当前窗口针对Windows的位置,x,y
driver.set_window_position(20,20)
 
# 最大化当前窗口,不需要传参
driver.maximize_window()
 
# 返回当前操作的浏览器句柄
driver.current_window_handle
 
# 返回所有打开server的浏览器句柄
driver.window_handles

截取当前页面

# 获取当前页面的二进制图片数据,需要自己去写入文件
driver.get_screenshot_as_png()
 
# as_png的上层封装,只需要传入图片名称自动写成图片
driver.get_screenshot_as_file('fileName.png')

执行JavaScript语句

# 执行JavaScript语句
driver.execute_script('JavaScript Commond')
 
# 例:
# 通过js来操作滚动条
# 参数1:x  参数2: y
window.scrollTo(100,400);

关闭与退出

# 当开启多个时,关闭当前页面
driver.close()
 
# 退出并关闭所有页面驱动
driver.quit()

其他

# 返回页面源码
driver.page_source
 
# 返回tag标题
driver.title
 
# 返回当前Url
driver.current_url
 
# 获取浏览器名称 如:chrome
driver.name

ElementApi接口

# 根据标签属性名称,获取属性value
element.get_attribute('style')
 
# 向输入框输入字符串 如果input的type为file类型 可以输入文件绝对路径上传文件
element.send_keys()
 
# 清除文本内容
element.clear()
 
# 鼠标左键点击操作
element.click()
 
# 通过属性名称获取属性
element.get_property('id')
 
# 返回元素是否可见 True or False
element.is_displayed()
 
# 返回元素是否被选中 True or False
element.is_selected()
 
# 返回标签元素的名字
element.tag_name
 
# 获取当前标签的宽和高
element.size
 
# 获取元素的文本内容
element.text
 
# 模仿回车按钮 提交数据
element.submit()
 
# 获取当前元素的坐标
element.location
 
# 截取图片
element.screenshot()

常见异常

NoSuchElementException:没有找到元素
NoSuchFrameException:没有找到iframe
NoSuchWindowException:没找到窗口句柄handle
NoSuchAttributeException:属性错误
NoAlertPresentException:没找到alert弹出框
ElmentNotVisibleException:元素不可见
ElementNotSelectableException:元素没有被选中
TimeoutException:查找元素超时

Linux

ssh隧道技术

通过一个中间服务器,访问另一个服务器。

  • 需要访问234.234.234.234的FTP服务,也就是端口21
  • 中间服务器是123.123.123.123

    现在我们使用下面这条命令来达成我们的目的
ssh -N -f -L 2121:234.234.234.234:21 123.123.123.123
ftp localhost:2121 #

现在访问本地2121端口,就能连接234.234.234.234的21端口了

这里我们用到了SSH客户端的三个参数,下面我们一一做出解释:

  • -N 告诉SSH客户端,这个连接不需要执行任何命令。仅仅做端口转发
  • -f 告诉SSH客户端在后台运行
  • -L 做本地映射端口,被冒号分割的三个部分含义分别是
需要使用的本地端口号
需要访问的目标机器IP地址(IP: 234.234.234.234)
需要访问的目标机器端口(端口: 21)

最后一个参数是我们用来建立隧道的中间机器的IP地址(IP: 123.123.123.123)

我们再重复一下-L参数的行为。

-L X:Y:Z的含义是,将IP为Y的机器的Z端口通过中间服务器映射到本地机器的X端口。

在这条命令成功执行之后,我们已经具有绕过公司防火墙的能力,并且成功访问到了我们喜欢的一个FTP服务器了。

如何修改root密码?

  • root初始密码是随机分配的
    • 首先使用su passwd输入当前密码
    • 设置新密码
    • 使用su root
    • 输入新设置的密码即可

动态扩容:当我们的虚拟机初始的硬盘空间过小,可以动态扩容。

  • 启动Ubuntu,root用户登录。
  • 在终端输入:fdisk -l ,可以看到
----------------------------------------------------------------------------
Disk /dev/sda: 10.7 GB, 10737418240 bytes
255 heads, 63 sectors/track, 1305 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x000af383

Device Boot         Start         End      Blocks   Id System
/dev/sda1   *           1        1244     9992398+  83 Linux
/dev/sda2            1245        1305      489982+   5 Extended
/dev/sda5            1245        1305      489951   82 Linux swap / Solaris

Disk /dev/sdb: 5368 MB, 5368709120 bytes
255 heads, 63 sectors/track, 652 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00000000

Disk /dev/sdb doesn't contain a valid partition table
----------------------------------------------------------------------------
  • 这里可以看到/dev/sdb 就是我们新添加的硬盘,我们需要给新的硬盘分区。

  • 在终端输入:fdisk /dev/sdb

    • 之后键入:m,可以看到帮助信息,
    • 键入:n,添加新分区
    • 键入:p,选择添加主分区
    • 键入:1,选择主分区编号为1,这样创建后的主分区为sdb1
      之后,fdisk会让你选择该分区的开始值和结束值,直接回车
    • 最后键入:w,保存所有并退出,完成新硬盘的分区。
  • 格式化磁盘

    • 用ext3格式对/dev/sdb1 进行格式化,在终端输入:
mkfs -t ext3 /dev/sdb1 
  • 挂载该分区:
    • 手动挂载:
      • 在终端输入:mkdir /data ,创建新的硬盘的挂载点
      • 在终端键入:mount /dev/sdb1 /data ,将该新分区挂载到/data/这个目录下开机自动挂载
      • 修改/etc/fstab文件,添加如下行:
/dev/sdb1       /data      ext3    defaults,        0       1     
  • 有时候是我们的根分区不够了(/),此时可以采用 ln -s 软连接的方式进行挂在。

现在,硬盘中多出来的这5G空间,只有在/data下才能用,在其它地方,使用的依然是system分区——也就是原来的空间。但我要在其它地方存文件怎么办呢,可以用link来解决——把新分区中的内容映射到某个旧分区上,这样占用的新分区的空间,看起来确是存在旧分区某个你需要的位置。

比如我们/usr/local/hadoop文件大太大,

命令例子:

mv /usr/local/hadoop /data
ln -s /data/hadoop /usr/local/hadoop

这样,就可以像原来那样在/usr/local/hadoop 下做任何操作了,而它们实际发生在/data/hadoop下。

解决unable to lock the administration directory (/var/lib/dpkg/) is another process using it问题

一旦你运行了 apt-get 或者 apt 命令,锁定文件将会创建于 /var/lib/apt/lists/、/var/lib/dpkg/、/var/cache/apt/archives/ 中。

  • 找出并杀掉所有 apt-get 或者 apt 进程
root@ubuntu:~# ps -A | grep apt
19389 pts/0    00:00:00 apt-get
root@ubuntu:~# kill -9 19389
  • 删除锁定的文件
    • 首先运行下面的命令来移除 /var/lib/dpkg/ 文件夹下的锁定文件:
    $ sudo rm /var/lib/dpkg/lock
    
    • 强制重新配置软件包:
    $ sudo dpkg --configure -a
    
    • 也可以删除 /var/lib/apt/lists/ 以及缓存文件夹下的锁定文件:
    $ sudo rm /var/lib/apt/lists/lock
    $ sudo rm /var/cache/apt/archives/lock
    
    • 更新你的软件包源列表:
    $ sudo apt update
    或者
    $ sudo apt-get update
    

网络重启失败

  • 一般使用
sudo service network restart
  • 如果无效就直接使用
sudo service network-manager restart
  • 如果还无效,就使用以下代码
chkconfig network off
chkconfig network on
service NetworkManager stop
service NetworkManager start
这命令的意思是:重新运行网络管理装置

查看与用户相关文件命令

1.cat
2.more 只能向后查看
3.less 可以向前和向后查看,使用pageup和pagedown
4.head /etc/passwd #查看文件的前十行
5.head -2 /etc/passwd #查看文件的前两行
6.tail /etc/passwd #查看文件的后十行
7.tail -f /etc/passwd #实时跟踪文件
8.tail -2 /etc/passwd #查看文件的后两行
9.wc -l /etc/passwd #显示文件的行数
10.nl /etc/passwd #直接打印文件内容并且显示行号

新建用户和用户组

建用户

adduser ftpuser //新建ftpuser用户
passwd ftpuser //给ftpuser用户设置密码

建工作组

groupadd jggroup //新建test工作组

新建用户同时增加工作组

useradd -g jggroup ftpuser  //新建phpq用户并增加到test工作组
注::-g 所属组 -d 家目录 -s 所用的SHELL

给已有的用户增加工作组

usermod -G groupname username

修改用户家文件

nano /etc/passwd 将对应用户的目录进行修改。
useradd -d /home/ftpuser -m jggroup -s  /bin/bash -d指定用户主目录路径
rm -rf /var/spool/mail/jgftpuser  //如果有提示说未删除干净,就要使用这条命令

su切换的时候出现bash$

cp /etc/skel/.bash_logout ./
cp /etc/skel/.bash_profile ./
cp /etc/skel/.bashrc ./

yum安装ftp服务器

yum install -y vsftpd //安装
service vsftpd start //启动
systemctl enable vsftpd.service //开机启动
netstat -ntulp | grep ftp //查看端口号

yum安装firewall

#先检查是否安装了iptables
service iptables status
#安装iptables
yum install -y iptables
#升级iptables
yum update iptables 
#安装iptables-services
yum install iptables-services
  • 禁用/停止自带的firewalld服务
#停止firewalld服务
systemctl stop firewalld
#禁用firewalld服务
systemctl mask firewalld
  • 设置现有规则
#查看iptables现有规则
iptables -L -n
#先允许所有,不然有可能会杯具
iptables -P INPUT ACCEPT
#清空所有默认规则
iptables -F
#清空所有自定义规则
iptables -X
#所有计数器归0
iptables -Z
#允许来自于lo接口的数据包(本地访问)
iptables -A INPUT -i lo -j ACCEPT
#开放22端口
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
#开放21端口(FTP)
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
#开放80端口(HTTP)
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
#开放443端口(HTTPS)
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
#允许ping
iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT
#允许接受本机请求之后的返回数据 RELATED,是为FTP设置的
iptables -A INPUT -m state --state  RELATED,ESTABLISHED -j ACCEPT
#其他入站一律丢弃
iptables -P INPUT DROP
#所有出站一律绿灯
iptables -P OUTPUT ACCEPT
#所有转发一律丢弃
iptables -P FORWARD DROP
  • 其他规则设定
#如果要添加内网ip信任(接受其所有TCP请求)
iptables -A INPUT -p tcp -s 45.96.174.68 -j ACCEPT
#过滤所有非以上规则的请求
iptables -P INPUT DROP
#要封停一个IP,使用下面这条命令:
iptables -I INPUT -s ***.***.***.*** -j DROP
#要解封一个IP,使用下面这条命令:
iptables -D INPUT -s ***.***.***.*** -j DROP
  • 保存规则设定
#保存上述规则
service iptables save
  • 开启iptables服务
#注册iptables服务
#相当于以前的chkconfig iptables on
systemctl enable iptables.service
#开启服务
systemctl start iptables.service
#查看状态
systemctl status iptables.service

yum安装rz

yum install lrzsz -y

yum安装mysql

安装

# 查看所有的mysql
[root@liang ~]# yum list | grep mysql 
# 下载
[root@liang ~]# yum install -y mysql-server mysql mysql-devel
[root@liang ~]# yum install -y mariadb-server

启动&&停止 数据库字符集设置

# 配置mysql文件
[root@liang ~]# nano /etc/my.cnf 
# 加入配置参数
[root@liang ~]# character-set-server=utf8 
# 启动mysql服务
[root@liang ~]# service mysqld start
# 或者下面这个
[root@liang ~]# /etc/init.d/mysqld start
# 设置开机启动
[root@liang ~]# chkconfig --add mysqld
[root@liang ~]# chkconfig mysqld on
# 查看开机启动设置是否成功
[root@liang ~]# chkconfig --list | grep mysql* 
# 0:关闭 1:关闭 2:启用 3:启用 4:启用 5:启用 6:关闭停止
[root@liang ~]# mysqld 

默认密码修改

# 新版本的Mysql会为root用户创建一个初始密码,需要更改。
# 查看默认密码:
[root@VM_178_1_centos app]# sudo grep 'temporary password' /var/log/mysqld.log
2018-07-25T08:22:23.085633Z 1 [Note] A temporary password is generated for root@localhost: SaK7ekq+NGnv
# 使用该初始密码登陆mysql:mysql -uroot -pSaK7ekq+NGnv
[root@VM_178_1_centos app]# mysql -uroot -pSaK7ekq+NGnv
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.7.22

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
# 修改密码:
# 修改密码最小长度策略:
mysql> set global validate_password_length=0;
# 修改密码强度检查等级策略,0/LOW、1/MEDIUM、2/STRONG:
mysql> set global validate_password_policy=0;
# 修改密码:
mysql> set password for 'root'@'localhost' = password('root123');
------------------------------
mysql> set global validate_password_length=0;
Query OK, 0 rows affected (0.00 sec)

mysql> set global validate_password_policy=0;
Query OK, 0 rows affected (0.00 sec)

mysql> set password for 'root'@'localhost' = password('yu120123');
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> 

忘记root密码

  • 修改mysql不用密码登录
nano /etc/my.cnf
在[mysqld]下加入:
skip-grant-tables
  • 重启MySQL服务
service mysqld restart
  • 使用命令进入,密码为空
mysql -uroot -p
然后直接回车 
  • 输入
# 使用mysql数据库
mysql> use mysql;
#重设密码
mysql> UPDATE user SET PASSWORD =password("passwd") WHERE USER= 'root';
#注意:5.7版本password 字段改成authentication_string  password函数还是原来的password函数,即:
mysql> update user set authentication_string=password('passwd') where user='root';
  • 授权
GRANT privileges ON databasename.tablename TO 'username'@'host'
说明:
privileges:用户的操作权限,如SELECT,INSERT,UPDATE等,如果要授予所的权限则使用ALL
databasename:数据库名
tablename:表名,如果要授予该用户对所有数据库和表的相应操作权限则可用*表示,如*.*

例:

GRANT SELECT, INSERT ON test.user TO 'pig'@'%';
GRANT ALL ON *.* TO 'pig'@'%';
GRANT ALL ON maindataplus.* TO 'pig'@'%';

注意:
用以上命令授权的用户不能给其它用户授权,如果想让该用户可以授权,用以下命令:

GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION;
  • 刷新权限
mysql> flush privileges;
exit;
  • 修改回权限策略
nano /etc/my.cnf
删除:
skip-grant-tables
  • 重启mysql服务
service mysqld restart

mysql允许远程访问

# 第一个itoffice表示用户名,%表示所有的电脑都可以连接,也可以设置某个ip地址运行连接,第二个itoffice表示密码
mysql> GRANT ALL PRIVILEGES ON *.* TO 'itoffice'@'%' IDENTIFIED BY 'itoffice' WITH GRANT OPTION;
# 刷新权限
mysql> flush privileges;

mysql 新建用户

#创建一个名为:test 密码为:1234 的用户。
insert into mysql.user(Host,User,Password) values("localhost","test",password("1234"));
此时,此处的"localhost",是指该用户只能在本地登录,不能在另外一台机器上远程登录。如果想远程登录的话,将"localhost"改为"%",表示在任何一台电脑上都可以登录。也可以指定某台机器可以远程登录。

这种方式如果不行,说明数据库版本不正确,可以使用以下命令:

CREATE USER 'username'@'host' IDENTIFIED BY 'password';

#修改指定用户的密码

update user set password=password('xxx') where user='xxx';

mysql 授权

#授权admin用户拥有mydb数据库的所有权限。
>grant all privileges on mydb.* to admin@localhost identified by 'admin';

mysql 撤销授权

REVOKE ALL PRIVILEGES ON qr.* FROM 'eye'@'%';

mysql强制转换utf8

ALTER TABLE s_blog MODIFY COLUMN BlogSourceUrl VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

centos7下解决yum install mysql-server没有可用包

  • 安装从网上下载文件的wget命令
[root@master ~]# yum -y install wget
  • 下载mysql的repo源
[root@master ~]# wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 
  • 安装mysql-community-release-el7-5.noarch.rpm包
[root@master ~]# rpm -ivh mysql-community-release-el7-5.noarch.rpm
  • 查看下
[root@master ~]# ls -1 /etc/yum.repos.d/mysql-community*
/etc/yum.repos.d/mysql-community.repo
/etc/yum.repos.d/mysql-community-source.repo

会获得两个mysql的yum repo源:/etc/yum.repos.d/mysql-community.repo,/etc/yum.repos.d/mysql-community-source.repo。

  • 安装mysql
[root@master ~]# yum install mysql-server

yum安装redis

查看是否有redis yum 源

yum install redis

下载fedora的epel仓库

yum install epel-release

安装redis数据库

yum install redis

开启redis服务

service redis start  Redirecting to /bin/systemctl start redis.service

开启方式二

redis-server /etc/redis.conf  

查看redis是否开启

ps -ef | grep redis

进入redis服务

redis-cli

关闭服务

redis-cli  shutdown

开放端口6379、6380的防火墙

注意:配置文件是:/etc/sysconfig/iptables
以下是命令的方式:
/sbin/iptables -I INPUT -p tcp --dport 6379  -j ACCEPT  开启6379
/sbin/iptables -I INPUT -p tcp --dport 6380 -j ACCEPT  开启6380
/etc/rc.d/init.d/iptables save #保存

防火墙规则例子:

//禁止IP为192.168.1.5的主机从eth0访问本机
iptables -t filter -A INPUT -s 192.168.1.5 -i eth0 -j DROP
//禁止子网192.168.5.0访问web服务
iptables -t filter -I INPUT 2 -s 192.168.5.0/24 -p tcp --dport 80 -j DROP
//禁止IP为192.168.7.9访问FTP服务
iptables -t filter -I INPUT 2 -s 192.168.7.9 -p tcp --dport ftp -j DROP
//查看filter表中INPUT链的规则
iptables -t filter -L INPUT
//删除nat表中的所有规则
iptables -t nat -F
//禁止访问www.playboy.com网站
iptables -I FORWARD -d wwww.playboy.com -j DROP
//禁止192.168.5.23上网
iptables -I FORWARD -s 192.168.5.23 -j DROP

搭建Redis集群

  • 准备两台机器
  • 一台安装2个Redis(6379,6382):
#mkdir /usr/local/redis-cluster/6379
#mkdir /usr/local/redis-cluster/6382
  • 另一台安装4个redis(6380,6381,6383,6384):
#mkdir /usr/local/redis-cluster/6380
#mkdir /usr/local/redis-cluster/6381
#mkdir /usr/local/redis-cluster/6383
#mkdir /usr/local/redis-cluster/6384
  • 解压redis压缩包:
#tar -zxf redis3.0.4.tar.gz
  • 创建bin,复制redis里面的src下所有的文件:
#mkdir /usr/local/redis-cluster/bin
#cp xxx/redis3.0.4/src/* /usr/local/redis-cluster/bin
  • 复制redis3.0.4下所有的文件到每一个文件夹下:
#cp xxx/redis3.0.4/* /usr/local/redis-cluster/6379
#cp xxx/redis3.0.4/* /usr/local/redis-cluster/6380
#cp xxx/redis3.0.4/* /usr/local/redis-cluster/6381
#cp xxx/redis3.0.4/* /usr/local/redis-cluster/6382
#cp xxx/redis3.0.4/* /usr/local/redis-cluster/6383
#cp xxx/redis3.0.4/* /usr/local/redis-cluster/6384
  • 创建数据文件data:
#mkdir -p 6379/data 6380/data 6381/data 6382/data 6383/data 6384/data
  • 修改每个redis.conf,添加以下内容:
port 6379(每个节点的端口号)
daemonize yes
bind 10.50.7.32(绑定当前机器 IP)
dir /usr/local/redis-cluster/9001/data/(数据文件存放位置)
pidfile /var/run/redis_9001.pid(pid 6379和port要对应)
并取消以下三个的注释:
cluster-enabled yes(启动集群模式)
cluster-config-file nodes6379.conf(6379和port要对应)
cluster-node-timeout 15000
appendonly yes
  • 启动redis,并且指定配置文件:
/usr/local/bin/redis-server /usr/local/redis-cluster/6379/redis.conf
  • 安装集群所需软件:由于 Redis 集群需要使用 ruby 命令,所以我们需要安装 ruby 和相关接口。
#yum install ruby
#yum install rubygems
#gem install redis 
  • 为redis创建主从同步:
#/usr/local/redis-cluster/bin/redis-trib.rb create --replicas 1 10.50.7.32:6379 10.50.7.32:6380 10.50.7.31:6381 10.50.7.32:6382 10.50.7.32:6383 10.50.7.31:6384
  • 启动cli可测试:
#/usr/local/redis-cluster/bin/redis-cli -c -h 10.50.7.32 -p 6379

yum安装jps

yum list |grep jdk-devel
yum install java-1.8.0-openjdk-devel.x84_64

安装telnet

  • 先看服务器是否安装了telnet
rpm -qa | grep telnet
  • telnet 是挂在 xinetd 底下的,所以同时查看是否安装了xinetd服务
rpm -qa | grep xinetd
  • 两者都没有的安装的话,yum安装以下服务
yum install xinetd telnet telnet-server -y
  • 配置telnet
#设置开机启动
#chkconfig telnet on
#修改配置文件
vi /etc/xinetd.d/telnet
#将”disable= yes”改成” disable=no”
#激活服务
service xinetd restart
#防火墙配置(开启23端口)(如果没有防火墙,要先安装防火墙:
yum install iptables-services):
iptables -I INPUT -p tcp --dport 23 -jACCEPT
iptables -I INPUT -p udp --dport 23 -jACCEPT
service iptables save //保存
service iptables restart //重启防火墙
#再次激活服务
service xinetd restart
#使用telnet 连接测试数据库:
telnet 10.0.210.33 1521
#部署cdservice到tomcat目录下
#启动tomcat,看是否有报错信息

RPM 安装操作

rpm -i 需要安装的包文件名 
举例如下: 
rpm -i example.rpm 安装 example.rpm 包; 
rpm -iv example.rpm 安装 example.rpm 包并在安装过程中显示正在安装的文件信息; 
rpm -ivh example.rpm 安装 example.rpm 包并在安装过程中显示正在安装的文件信息及安装进度; 
RPM 查询操作 
命令: 
rpm -q … 
附加查询命令: 
a 查询所有已经安装的包以下两个附加命令用于查询安装包的信息; 
i 显示安装包的信息; 
l 显示安装包中的所有文件被安装到哪些目录下; 
s 显示安装版中的所有文件状态及被安装到哪些目录下;以下两个附加命令用于指定需要查询的是安装包还是已安装后的文件; 
p 查询的是安装包的信息; 
f 查询的是已安装的某文件信息; 
举例如下: 
rpm -qa | grep tomcat4 查看 tomcat4 是否被安装; 
rpm -qip example.rpm 查看 example.rpm 安装包的信息; 
rpm -qif /bin/df 查看/bin/df 文件所在安装包的信息; 
rpm -qlf /bin/df 查看/bin/df 文件所在安装包中的各个文件分别被安装到哪个目录下; 
RPM 卸载操作 
命令: 
rpm -e 需要卸载的安装包 
在卸载之前,通常需要使用rpm -q …命令查出需要卸载的安装包名称。 
举例如下: 
rpm -e tomcat4 卸载 tomcat4 软件包 
RPM 升级操作 
命令: 
rpm -U 需要升级的包 
举例如下: 
rpm -Uvh example.rpm 升级 example.rpm 软件包 
RPM 验证操作 
命令: 
rpm -V 需要验证的包 
举例如下: 
rpm -Vf /etc/tomcat4/tomcat4.conf 
输出信息类似如下: 
S.5….T c /etc/tomcat4/tomcat4.conf 
其中,S 表示文件大小修改过,T 表示文件日期修改过。限于篇幅,更多的验证信息请您参考rpm 帮助文件:man rpm 
RPM 的其他附加命令 
–force 强制操作 如强制安装删除等; 
–requires 显示该包的依赖关系; 
–nodeps 忽略依赖关系并继续操作

云服务器与本地服务器搭建vpn

普通本机电脑是无法直接暴露给外网访问的,如果需要做负载可以通过VPN,步骤如下:

原理

云服务安装VPN客户端,启用服务,本地服务器连接云服务器

# 云服务器安装VPN客户端:
下载文件:
yum install ppp pptp pptp-setup
下载并安装VPN客户端:
rpm -ivh pptp-release-current.noarch.rpm 
# 配置文件:
 echo "localip 9.0.0.1" >>/etc/pptpd.conf
 echo "remoteip 9.0.0.100-200" >>/etc/pptpd.conf
 echo "vpn4 pptpd vpn4 1.9.9.8" >>/etc/ppp/chap-secrets
启动:
service pptpd start
# 本地服务器安装VPN客户端:
下载文件:
yum install ppp pptp pptp-setup
拨号:
pptpsetup --create 1 --server 云服务器ip  --username vpn4 --password vpn4 --encrypt --start
需要使用--encrypt,不然会报timeout,因为加密不对称。
# 如果在云服务器端ifconfig能看到ppp0这个虚拟网卡,则说明连接成功!
# 云服务器上:ping 1.9.9.8可以看到效果,并且可以使用talent连接
# 如果发现第二天无法ping通了,可以使用转发来解决:
iptables -t nat -A POSTROUTING -s 1.9.9.0/24 -o eth0 -j MASQUERADE

zookeeper

zookeeper 安装

下载地址:

链接:https://pan.baidu.com/s/1Sc-hlTRkIfKYyyALkH9lLA 
提取码:8twq 

安装及配置

上传zookeeper-3.4.10的安装包;
解压到software下;
进入zookeeper-3.4.10创建文件夹data;
在data下创建文件myid,内容是1;
进入conf,复制一份zoo_sample.cfg命名为zoo.cfg;
修改zoo.cfg内容:
dataDir=/software/zookeeper-3.4.10/data
最后一行添加:
server.1=slave01:2888:3888
server.2=salve02:2888:3888
server.3=slave03:2888:3888

基本使用

linux:./zkServer.sh start|start-foreground 启动zkServer
windows: zkCli.cmd -server ip:2181 #连接到指定ip的zookeeper

zookeeper主要是配置一个dataDir,不要配置到/tmp目录下,Linux开机重启会清空这个目录。

zkui 安装

下载地址:

https://github.com/DeemOpen/zkui

zkui 配置

将yml或properties文件保存为txt格式的文件,导入文件的配置规则:

/config/{application-name},{profile}={key}={value}

其中{application-name}与{profile}之间用逗号分隔,也可以定义其他分隔符号,在上述bootstrap文件中根据spring.cloud.zookeeper.config.profileSeparator指定。
例:

/config/demo,dev=spring.datasource.url=jdbc:mysql://192.168.0.176:3306/world?characterEncoding=utf8&useSSL=false
 
/config/demo,dev=spring.datasource.username=root
 
/config/demo,dev=spring.datasource.password=123456
 
/config/demo,dev=spring.datasource.driver-class-name=com.mysql.jdbc.Driver
 
/config/demo,dev=mybatis.mapper-locations=classpath*:/mapper/**Mapper.xml

然后,application文件要指定profile,它的值要和ZooKeeper配置中的{profile}一致。

spring:
  profiles:
    active: dev

kafka

kafka安装

下载地址:http://mirrors.tuna.tsinghua.edu.cn/apache/kafka/2.3.0/kafka_2.12-2.3.0.tgz

kafka配置

解压下载的kafka

cd  /usr/local
tar -xzf kafka_2.11-2.0.0.tgz
cd kafka_2.11-2.0.0

启动服务

启动zookeeper

启动zk有两种方式,第一种是使用kafka自己带的一个zk。

bin/zookeeper-server-start.sh  config/zookeeper.properties 

另一种是使用其它的zookeeper,可以位于本机也可以位于其它地址。
这种情况需要修改config下面的sercer.properties里面的zookeeper地址 。

例如zookeeper.connect=192.168.213.11:2181

成功启动zookeeper后才可以启动kafka。

启动 kafka
bin/kafka-server-start.sh config/server.properties
创建topic
[root@bogon kafka_2.11-2.0.0]# 
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test

创建一个名为test的topic,只有一个副本,一个分区。
通过list命令查看刚刚创建的topic

bin/kafka-topics.sh -list -zookeeper localhost:2181
启动producer并发送消息启动producer
[root@bogon kafka_2.11-2.0.0]#
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test

启动之后就可以发送消息了
比如

>test
>hello boy
在另一个终端中启动consumer

以下是旧版本的命令:

bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic test --from-beginning

报错:consumer zookeeper is not a recognized option
发现在启动的时候说使用 --zookeeper是一个过时的方法,最新的版本中命令如下:

bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning

启动consumer之后就可以在console中看到producer发送的消息了
可以开启两个终端,一个发送消息,一个接受消息。

删除kafka中的topic方法
  • 删除topic,慎用,只会删除zookeeper中的元数据,消息文件须手动删除
bin/kafka-run-class.sh kafka.admin.DeleteTopicCommand --zookeeper node01:2181 --topic topicname

如命令如果报错,可能因为是版本的问题,也可以单独执行下面的命令

bin/kafka-topics.sh --delete --zookeeper host:port --topic topicname
  • 消息文件手动删除 topic,
    • 删除日志目录下的topic相关文件
    • 删除zookeeper里的数据 登录zookeeper客户端
      cd $ZOOKEEPER_HOME bin/zkCli.sh  
    
    • 删除
    ls /config/topics/topicname 
    ls /brokers/topics/topicname
    

以上两步全执行才会彻底删除

如:删除kafka存储目录(server.properties文件log.dirs配置,默认为"/tmp/kafka-logs"),相关topic目录删除zookeeper

cd $ZOOKEEPER_HOME bin/zkCli.sh .
rmr /config/topics/topicname
rmr /brokers/topics/topicname

附:kafka 删除topic 提示marked for deletion
并没有真正删除,如果要真正删除
在每一台机器中的kafka安装目录/config/server.properties 文件加入

delete.topic.enable=true

最后所有机器重新启动kafka

Shell脚本

#!/bin/bash 
#!是一个特殊的表示符,其后,跟着解释此脚本的shell路径。
bash只是shell的一种,还有很多其它shell,如:sh,csh,ksh,tcsh,...

判断文件或文件夹是否存在

  • 文件夹不存在则创建
if [ ! -d "/data/" ];then
mkdir /data
else
echo "文件夹已经存在"
fi
  • 文件存在则删除
if [ ! -f "/data/filename" ];then
echo "文件不存在"
else
rm -f /data/filename
fi
  • 判断文件夹是否存在
if [ -d "/data/" ];then
echo "文件夹存在"
else
echo "文件夹不存在"
fi
  • 判断文件是否存在
if [ -f "/data/filename" ];then
echo "文件存在"
else
echo "文件不存在"
fi
  • 文件比较符
    • e 判断对象是否存在
    • d 判断对象是否存在,并且为目录
    • f 判断对象是否存在,并且为常规文件
    • L 判断对象是否存在,并且为符号链接
    • h 判断对象是否存在,并且为软链接
    • s 判断对象是否存在,并且长度不为0
    • r 判断对象是否存在,并且可读
    • w 判断对象是否存在,并且可写
    • x 判断对象是否存在,并且可执行
    • O 判断对象是否存在,并且属于当前用户
    • G 判断对象是否存在,并且属于当前用户组
    • nt 判断file1是否比file2新 [ "/data/file1" -nt "/data/file2" ]
    • ot 判断file1是否比file2旧 [ "/data/file1" -ot "/data/file2" ]

if-then-else语句

if  command
then
    command
fi
------------
if  command
then
    command
else
    command
fi

开机启动

zookeeper开机启动

  • 新建zookeeper
vi zookeeper
  • 修改内容
#!/bin/bash

export JAVA_HOME=/opt/jdk1.8.0_161
export PATH=$JAVA_HOME/bin:$PATH 

#chkconfig:2345 20 90
#description:zookeeper
#processname:zookeeper
case $1 in
          start) 
              /opt/zookeeper/zookeeper-3.4.9/bin/zkServer.sh start
              ;;
          stop)
              /opt/zookeeper/zookeeper-3.4.9/bin/zkServer.sh stop
              ;;
          status)
              /opt/zookeeper/zookeeper-3.4.9/bin/zkServer.sh status
              ;;
          restart)
              /opt/zookeeper/zookeeper-3.4.9/bin/zkServer.sh restart
              ;;
          *)
              echo "require start|stop|status|restart"
              ;;
esac
  • 修改权限
chmod 755 zookeeper
  • 测试命令
service zookeeper status
  • 添加到服务列表
chkconfig --add zookeeper
  • 验证
chkconfig --list
  • 设置为开机启动
chkconfig zookeeper on

kafka开机启动

  • 打开目录
cd /etc/init.d/
  • 新建kafka
vi kafka
  • 修改内容
#!/bin/bash

export JAVA_HOME=/opt/jdk1.8.0_161
export PATH=$JAVA_HOME/bin:$PATH 

#chkconfig:2345 20 90
#description:kafka
#processname:kafka
case $1 in
          start) 
              /opt/kafka_2.10-0.10.2.0/bin/kafka-server-start.sh -daemon /opt/kafka_2.10-0.10.2.0/config/server.properties
              ;;
          stop)
               /opt/kafka_2.10-0.10.2.0/bin/kafka-server-stop.sh
              ;;
          status)
              jps
              ;;
          restart)
              /opt/kafka_2.10-0.10.2.0/bin/kafka-server-stop.sh
              /opt/kafka_2.10-0.10.2.0/bin/kafka-server-start.sh -daemon /opt/kafka_2.10-0.10.2.0/config/server.properties
              ;;
          *)
              echo "require start|stop|status|restart"
              ;;
esac
  • 修改权限
chmod 755 kafka
  • 测试命令
service kafka status
  • 添加到服务列表
chkconfig --add kafka
  • 验证
chkconfig --list
  • 设置为开机启动
chkconfig kafka on

Linux命令

netstat常见参数

-a (all)显示所有选项,默认不显示LISTEN相关
-t (tcp)仅显示tcp相关选项
-u (udp)仅显示udp相关选项
-n 拒绝显示别名,能显示数字的全部转化成数字。
-l 仅列出有在 Listen (监听) 的服务状态
-p 显示建立相关链接的程序名
-r 显示路由信息,路由表
-e 显示扩展信息,例如uid等
-s 按各个协议进行统计
-c 每隔一个固定时间,执行该netstat命令。
提示:LISTEN和LISTENING的状态只有用-a或者-l才能看到

wc: 统计

sed :stream editor

流编辑器,可以新增、删除、修改、替换文本内容,输出的内容不会覆盖原文本,可以使用-i参数来直接覆盖原文件。

用法:
sed -n 纯净模式,显示需要处理的内容。如果不加这个参数,则会显示过滤后的文本和原文本。
删除 d (delete):
sed '1d' 删除第一行
sed '$d' 删除最后一行
sed '1,3d' 删除第1到3行
打印 p(print):
sed '1p' 显示第一行
...类推
sed '/main/p' 搜索功能,显示含有main的行。
追加 a(append):
sed '1ahelloword' a.txt 往a.txt的第一行后面追加helloword。
sed '1a\ helloword' a.txt 使用\进行转义,带空格。
sed '1a\\helloword' a.txt 追加制表符。
sed '1,3a\ helloword' a.txt 1到3行每一行后面都追加helloworld。
插入 i(insert),与追加类似,只不过是在之前插入:
sed '1ihelloword' a.txt 往a.txt的第一行前面插入helloword。
覆盖 c(cover):
sed '1,2chelloword' a.txt 前两行替换成helloworld。
替换 s g (substitude):
sed 's/a/b/g' a.txt 用b替换a,s和g是固定写法,中间的斜杠可以使用正则匹配。

date

时间命令,可以对Linux时间进行格式化处理。
date [OPTION]... [+FORMAT]

$>date +%Y/%m/%d %H%M%S//%H:24小时
                        //%I:12小时
                        //%s:1970~
$>date -d "1 day" +%Y%m%d   //一天后
$>date -d "-1 days" +%Y%m%d //一天前
$>date -d "1 month" +%Y%m%d //一月后

cron

周期调度。

crontab -u ubuntu -e

分布式

消息队列

我们可以把消息队列比作是一个存放消息的容器,当我们需要使用消息的时候可以取出消息供自己使用。消息队列是分布式系统中重要的组件,使用消息队列主要是为了通过异步处理提高系统性能和削峰、降低系统耦合性。

通俗来讲

另外,我们知道队列 Queue 是一种先进先出的数据结构,所以消费消息时也是按照顺序来消费的。比如生产者发送消息1,2,3...对于消费者就会按照1,2,3...的顺序来消费。但是偶尔也会出现消息被消费的顺序不对的情况,比如某个消息消费失败又或者一个 queue 多个consumer 也会导致消息被消费的顺序不对,我们一定要保证消息被消费的顺序正确。

除了上面说的消息消费顺序的问题,使用消息队列,我们还要考虑如何保证消息不被重复消费?如何保证消息的可靠性传输(如何处理消息丢失的问题)?......等等问题。所以说使用消息队列也不是十全十美的,使用它也会让系统可用性降低、复杂度提高,另外需要我们保障一致性等问题。

为什么要使用消息队列

  • 通过异步处理提高系统性能(削峰、减少响应所需时间)。
  • 降低系统耦合性。

kafka

kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。

特性

  • 以时间复杂度为O(1)的方式提供消息持久化能力,即使对TB级以上数据也能保证常数时间复杂度的访问性能。
  • 高吞吐率。即使在非常廉价的商用机器上也能做到单机支持每秒100K条以上消息的传输。
  • 支持Kafka Server间的消息分区,及分布式消费,同时保证每个Partition内的消息顺序传输。
  • 同时支持离线数据处理和实时数据处理。
  • Scale out:支持在线水平扩展。

术语

Broker

Kafka集群包含一个或多个服务器,这种服务器被称为broker。

Topic

每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。(物理上不同Topic的消息分开存储,逻辑上一- - 个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处)

Partition

Partition是物理上的概念,每个Topic包含一个或多个Partition。

Producer

负责发布消息到Kafka broker。

Consumer

消息消费者,向Kafka broker读取消息的客户端。

Consumer Group

每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)。

Java开发

  • Maven依赖
<dependency>
    <groupId>org.apache.kafka</groupId>
     <artifactId>kafka_2.12</artifactId>
     <version>1.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
         <groupId>org.apache.kafka</groupId>
         <artifactId>kafka-clients</artifactId>
          <version>1.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.kafka</groupId>
        <artifactId>kafka-streams</artifactId>
        <version>1.0.0</version>
</dependency>
  • Kafka Producer
    常用配置说明
bootstrap.servers: kafka的地址。
acks:消息的确认机制,默认值是0。
acks=0:如果设置为0,生产者不会等待kafka的响应。
acks=1:这个配置意味着kafka会把这条消息写到本地日志文件中,但是不会等待集群中其他机器的成功响应。
acks=all:这个配置意味着leader会等待所有的follower同步完成。这个确保消息不会丢失,除非kafka集群中所有机器挂掉。这是最强的可用性保证。
retries:配置为大于0的值的话,客户端会在消息发送失败时重新发送。
batch.size:当多条消息需要发送到同一个分区时,生产者会尝试合并网络请求。这会提高client和生产者的效率。
key.serializer: 键序列化,默认org.apache.kafka.common.serialization.StringDeserializer。
value.deserializer:值序列化,默认org.apache.kafka.common.serialization.StringDeserializer。
... 
更多的参考查看官方文档。
http://kafka.apache.org/20/javadoc/index.html?org/apache/kafka/clients/producer/KafkaProducer.html

Java代码

Properties props = new Properties();
props.put("bootstrap.servers", "master:9092,slave1:9092,slave2:9092");
props.put("acks", "all");
props.put("retries", 0);
props.put("batch.size", 16384);
props.put("key.serializer", StringSerializer.class.getName());
props.put("value.serializer", StringSerializer.class.getName());
KafkaProducer<String, String> producer = new KafkaProducer<String, String>(props);

#kafka的配置添加之后,我们便开始生产数据,生产数据代码只需如下就行:

producer.send(new ProducerRecord<String, String>(topic,key,value));
  • topic: 消息队列的名称,可以先行在kafka服务中进行创建。如果kafka中并未创建该topic,那么便会自动创建!

  • key:键值,也就是value对应的值,和Map类似。

  • value:要发送的数据,数据格式为String类型的。

  • Kafka Consumer
    常用配置说明

bootstrap.servers: kafka的地址。
group.id:组名 不同组名可以重复消费。例如你先使用了组名A消费了kafka的1000条数据,但是你还想再次进行消费这1000条数据,并且不想重新去产生,那么这里你只需要更改组名就可以重复消费了。
enable.auto.commit:是否自动提交,默认为true。
auto.commit.interval.ms: 从poll(拉)的回话处理时长。
session.timeout.ms:超时时间。
max.poll.records:一次最大拉取的条数。
auto.offset.reset:消费规则,默认earliest 。
earliest: 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费 。
latest: 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据 。
none: topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常。
key.serializer: 键序列化,默认org.apache.kafka.common.serialization.StringDeserializer。
value.deserializer:值序列化,默认org.apache.kafka.common.serialization.StringDeserializer。

Java代码

Properties props = new Properties();
props.put("bootstrap.servers", "master:9092,slave1:9092,slave2:9092");
props.put("group.id", GROUPID);
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
props.put("session.timeout.ms", "30000");
props.put("max.poll.records", 1000);
props.put("auto.offset.reset", "earliest");
props.put("key.deserializer", StringDeserializer.class.getName());
props.put("value.deserializer", StringDeserializer.class.getName());
KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(props);

由于我这是设置的自动提交,所以消费代码如下:
我们需要先订阅一个topic,也就是指定消费哪一个topic。

consumer.subscribe(Arrays.asList(topic));

订阅之后,我们再从kafka中拉取数据:

ConsumerRecords<String, String> msgList=consumer.poll(1000);

activemq

rabbitmq

rocketmq

Idea

启动

Idea启动项目报错:Command line is too long. Shorten command line for className or also for JUnit defaultconfiguration.
image

解决方法:

在该项目文件夹.idea/workspace.xml中找到

<component name="PropertiesComponent">
</component>

然后在其中添加:

<property name="dynamic.classpath" value="true" />

或者

修改C:\Users\xiaobao\.IntelliJIdea2017.1\config\options\project.default.xml增加上述配置。

其他

MBR和GUID的区别

  • MBR:是传统的硬盘使用方式,只支持一个硬盘上最多4个主分区。
  • GUID:就是新兴的GPT方式,支持的主分区数量没有限制。

如果主板较老只支持BIOS,就选MBR,如果是新主板,支持UEFI,就可以选GUID。

Office设置目录

1、先设置文档中各级标题的级别。
选择 格式—段落—大纲级别(在目录中是标题几(你所说的几级标题)就设置成几级)
2、插入—引用—索引和目录—目录

Sublime Text 3 快捷键精华版

Sublime Text 3 快捷键精华版
Ctrl+Shift+P:打开命令面板
Ctrl+P:搜索项目中的文件
Ctrl+G:跳转到第几行
Ctrl+W:关闭当前打开文件
Ctrl+Shift+W:关闭所有打开文件
Ctrl+Shift+V:粘贴并格式化
Ctrl+D:选择单词,重复可增加选择下一个相同的单词
Ctrl+L:选择行,重复可依次增加选择下一行
Ctrl+Shift+L:选择多行
Ctrl+Shift+Enter:在当前行前插入新行
Ctrl+X:删除当前行
Ctrl+M:跳转到对应括号
Ctrl+U:软撤销,撤销光标位置
Ctrl+J:选择标签内容
Ctrl+F:查找内容
Ctrl+Shift+F:查找并替换
Ctrl+H:替换
Ctrl+R:前往 method
Ctrl+N:新建窗口
Ctrl+K+B:开关侧栏
Ctrl+Shift+M:选中当前括号内容,重复可选着括号本身
Ctrl+F2:设置/删除标记
Ctrl+/:注释当前行
Ctrl+Shift+/:当前位置插入注释
Ctrl+Alt+/:块注释,并Focus到首行,写注释说明用的
Ctrl+Shift+A:选择当前标签前后,修改标签用的
F11:全屏
Shift+F11:全屏免打扰模式,只编辑当前文件
Alt+F3:选择所有相同的词
Alt+.:闭合标签
Alt+Shift+数字:分屏显示
Alt+数字:切换打开第N个文件
Shift+右键拖动:光标多不,用来更改或插入列内容
鼠标的前进后退键可切换Tab文件
按Ctrl,依次点击或选取,可需要编辑的多个位置
按Ctrl+Shift+上下键,可替换行
选择类
Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本。
Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑。举个栗子:快速选中并更改所有相同的变量名、函数名等。
Ctrl+L 选中整行,继续操作则继续选择下一行,效果和 Shift+↓ 效果一样。
Ctrl+Shift+L 先选中多行,再按下快捷键,会在每行行尾插入光标,即可同时编辑这些行。
Ctrl+Shift+M 选择括号内的内容(继续选择父括号)。举个栗子:快速选中删除函数中的代码,重写函数体代码或重写括号内里的内容。
Ctrl+M 光标移动至括号内结束或开始的位置。
Ctrl+Enter 在下一行插入新行。举个栗子:即使光标不在行尾,也能快速向下插入一行。
Ctrl+Shift+Enter 在上一行插入新行。举个栗子:即使光标不在行首,也能快速向上插入一行。
Ctrl+Shift+[ 选中代码,按下快捷键,折叠代码。
Ctrl+Shift+] 选中代码,按下快捷键,展开代码。
Ctrl+K+0 展开所有折叠代码。
Ctrl+← 向左单位性地移动光标,快速移动光标。
Ctrl+→ 向右单位性地移动光标,快速移动光标。
shift+↑ 向上选中多行。
shift+↓ 向下选中多行。
Shift+← 向左选中文本。
Shift+→ 向右选中文本。
Ctrl+Shift+← 向左单位性地选中文本。
Ctrl+Shift+→ 向右单位性地选中文本。
Ctrl+Shift+↑ 将光标所在行和上一行代码互换(将光标所在行插入到上一行之前)。
Ctrl+Shift+↓ 将光标所在行和下一行代码互换(将光标所在行插入到下一行之后)。
Ctrl+Alt+↑ 向上添加多行光标,可同时编辑多行。
Ctrl+Alt+↓ 向下添加多行光标,可同时编辑多行。
编辑类
Ctrl+J 合并选中的多行代码为一行。举个栗子:将多行格式的CSS属性合并为一行。
Ctrl+Shift+D 复制光标所在整行,插入到下一行。
Tab 向右缩进。
Shift+Tab 向左缩进。
Ctrl+K+K 从光标处开始删除代码至行尾。
Ctrl+Shift+K 删除整行。
Ctrl+/ 注释单行。
Ctrl+Shift+/ 注释多行。
Ctrl+K+U 转换大写。
Ctrl+K+L 转换小写。
Ctrl+Z 撤销。
Ctrl+Y 恢复撤销。
Ctrl+U 软撤销,感觉和 Gtrl+Z 一样。
Ctrl+F2 设置书签
Ctrl+T 左右字母互换。
F6 单词检测拼写
搜索类
Ctrl+F 打开底部搜索框,查找关键字。
Ctrl+shift+F 在文件夹内查找,与普通编辑器不同的地方是sublime允许添加多个文件夹进行查找,略高端,未研究。
Ctrl+P 打开搜索框。举个栗子:1、输入当前项目中的文件名,快速搜索文件,2、输入@和关键字,查找文件中函数名,3、输入:和数字,跳转到文件中该行代码,4、输入#和关键字,查找变量名。
Ctrl+G 打开搜索框,自动带:,输入数字跳转到该行代码。举个栗子:在页面代码比较长的文件中快速定位。
Ctrl+R 打开搜索框,自动带@,输入关键字,查找文件中的函数名。举个栗子:在函数较多的页面快速查找某个函数。
Ctrl+: 打开搜索框,自动带#,输入关键字,查找文件中的变量名、属性名等。
Ctrl+Shift+P 打开命令框。场景栗子:打开命名框,输入关键字,调用sublime text或插件的功能,例如使用package安装插件。
Esc 退出光标多行选择,退出搜索框,命令框等。
显示类
Ctrl+Tab 按文件浏览过的顺序,切换当前窗口的标签页。
Ctrl+PageDown 向左切换当前窗口的标签页。
Ctrl+PageUp 向右切换当前窗口的标签页。
Alt+Shift+1 窗口分屏,恢复默认1屏(非小键盘的数字)
Alt+Shift+2 左右分屏-2列
Alt+Shift+3 左右分屏-3列
Alt+Shift+4 左右分屏-4列
Alt+Shift+5 等分4屏
Alt+Shift+8 垂直分屏-2屏
Alt+Shift+9 垂直分屏-3屏
Ctrl+K+B 开启/关闭侧边栏。
F11 全屏模式
Shift+F11 免打扰模式
配置编译环境
控制台输入(以C++为例)
原理很简单,就是在外部建立一个用来执行文件的 bat,然后调用它。注意的就是,需要用start 来打开一个新窗口,同时需要 pause 一下来看结果,其中很蛋疼的就是Sublime默认后台执行你的start,如果你的pause和start放在一个文件了pause对start %1 的文件是无效的,因此其实需要建立两个文件。注意环境变量。。。(关于什么是环境变量,三两句解释不清楚,最好自己百度一下。)
配好之后个人感觉控制台输入意义不是很大,做题的话都是从文件读入,做开发基本不需要读入。So~ 各位慎重。
MyCRun.bat
@echo off  
%1  
echo.  
echo -------------------  
pause  
exit  

MyCallRun.bat
@start  MyCRun %1  
配置文件在 Sublime Text 3\Packages\C++.sublime-package 。 先备份一下。
修改里面的 C++.sublime-build 为
{  
    "shell_cmd": "g++ \"${file}\" -o \"${file_path}/${file_base_name}\"",  
    "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",  
    "working_dir": "${file_path}",  
    "selector": "source.c, source.c++",  
    "variants":  
    [  
        {  
            "name": "Run",  
            "shell_cmd": "g++ \"${file}\" -o \"${file_path}/${file_base_name}\" && MyCallRun \"${file_path}/${file_base_name}.exe\""    //  其实就是这里加了个MyCallRun  
        }  
    ]  
}  
C/C++
Sublime Text 3 默认配置好了 c++ 。但是需要你自己把 gcc 目录添加进环境变量
Java
Sublime Text 3 默认只运行了 javac,需要自己添加运行。
苦逼看不懂 Sublime 的命令格式,于是把 javac 改成一个自己的bat。(感觉也可以像C++那样用 && 连起来)
在命令行可直接访问的地方建立 myJRun.bat (我直接放在 jdk/bin 下了)
@ECHO OFF    
cd %~dp1    
ECHO Compiling %~nx1...    
IF EXIST %~n1.class (    
DEL %~n1.class    
)    
javac %~nx1    
IF EXIST %~n1.class (    
ECHO Running...  
ECHO ----------------------OUTPUT----------------------  
java %~n1    
)  
注意不能使用 cls 。
修改java的编译选项(备份好原来的)。
目录:Packages/Java.sublime-package/JavaC.sublime-build
{  
    "shell_cmd": "myJRun.bat \"$file\"",  
    "file_regex": "^(...*?):([0-9]*):?([0-9]*)",  
    "selector": "source.java"  
}  
这样以后写的Java代码点 Build 就会自动运行了。
这种办法不能跨平台,再研究研究Sublime自己的方式。
Go
用 Sublime 开发 golang 的环境很简单,只需要安装一个 GoSublime 就差不多了。

计算机为什么要用补码

 如果按常规思路:
  1:  0000 0001
 -1:  1000 0001
-------------------
那么: 
1+(-1) =  1000 0010 = -2 
而现实中: 1+(-1) = 0
所以,计算机规定,负数有其特定的表示方式,就是:首先取负数的整数部分,然后按位取反,然后+1.
比如:-1 -->
       1 : 0000 0001 -->
           1111 1110 -->
      加1: 1111 1111

所以,-1的字节表示为:1111 1111  
现在,1+(-1) = 
  0000 0001
+ 1111 1111
----------------------  
1 0000 0000
前面的1会被截断,因为超出了存储范围。

1000

11 1110 1000

1110 1000
0001 0111
0001 1000 --> 2^4 + 2^3 = 16+8 = 24

0000 0011 --> 3


2534

1001 1110 0110
1110 0110
0001 1001
0001 1010 --> 2^4 + 2^3 + 2^1 = 16+8+2 = 26 --> -26

0000 1001 --> 2^3 + 2^0 = 8+1 =9

0000 0000 --> 0

0000 0000 --> 0

 
1110 0110 &
1111 1111
--------------   -26 & 0xFF
1110 0110

0000 1001 &
1111 1111
--------------   9 & 0xFF
0000 1001

0000 0000 0000 0000 0000 0000 1110 0110
0000 0000 0000 0000 0000 1001 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 
0000 0000 0000 0000 0000 0000 0000 0000

0000 0000 0000 0000 0000 1001 1110 0110

HTTP

HTTP协议

HTTP幂等性

  • 幂等:一次请求和多次请求的结果是一样的。
  • 支持幂等:PUT
  • 不支持幂等:POST

比如新增一条数据,如果DB的ID时自增的,且插入前不会先查询某个字段值是否存在,那么这个接口反复的调用就会产生多条新增的记录。

反之,如果每次新增前,我都先去库里查询一下当前新增的这个身份证号码是否已存在,已存在则不让其插入,那么这个接口就是幂等的。

简而言之,如果上游明确只操作一次,那么在经过HTTP流程的时候,PUT请求时不会产生多个请求,而POST则不一定的。

网络传输七层协议

在七层模型中,每个分层都接受由它下一层所提供的特定服务,并且负责为自己的上一层提供特定的服务,上下层之间进行交互所遵循的约定叫做“接口”,同一层之间的交互所遵循的约定叫做“协议”

应用层

针对特定应用的协议,如超文本传输协议(HTTP)、电子邮件(SMTP)、远程登录(TELNET)、文件传输(FTP)等。

表示层

设备固有数据格式和网络标准数据格式的转换。

会话层

通信管理。负责建立和断开连接。管理传输层以下的分层。

传输层

管理两个节点之间的数据传输。保证数据传输的可靠性。数据的单位称为数据段(segment

网络层

地址管理和路由选择。数据的单位称为数据包(packet

数据链路层

互连设备之间传送和识别数据帧。数据的单位称为帧(frame

物理层

以0、1代表电压的高低、灯光的闪灭。界定连接器和网线的规格。数据的单位称为比特(bit

数据库

事务

事务是指在连续操作多次数据(增删改查)的时候,保证每次操作都能成功。如果其中有一次失败,则之前的操作全部回滚。之后的操作也不会再进行。

事务隔离级别

事务隔离级别是为了保证多线程或并发的访问的情况下保证数据的完整性。

脏读

一个事务读取到另一个事务中未提交的数据,另一个事务可能对这个数据进行了改变。第一个事务读取出来的数据可能和数据库的不一致,此时认为第一个事务读取出来的数据是脏数据。

不可重复度

当事务A第一次读取数据后,事务B对事务A读取的数据进行修改,事务A中再次读取的数据和之前的数据不一致,称为不可重复读。如果满足这个条件,则在事务A读取数据后,事务B不能对这个数据进行修改操作,可以读,但是不能修改。故言之不可重复读。

  • 主要针对行数据或行中某列(行锁)
  • 两个读取在同一个事务内
  • 主要针对修改操作

幻读

事务A按照特定的条件查询出结果,事务B新增了一条符合条件的数据。事务A中查询出的数据和数据库中的不一致。事务A感觉出现了幻觉,故言之幻读。

  • 主要针对表(表锁)
  • 两次事务的结果
  • 主要针对新增和删除

Spring事务隔离取值

Spring事务隔离级别设置后,是告诉数据库将采用某种隔离级别来处理,而不是自身来处理。

READ_UNCOMMITIED

可以读取未提交的数据,可能出现脏读,不可重复度,幻读。最低级别的事务,但是效率最高。因为未加锁。

READ_COMMITIED

可以读取其他事务提交的数据,可以防止脏读,可能出现不可重复读,幻读。

REPEATABLE_READ

读取的数据加锁,可以防止脏读、不可重复度,可能出现幻读。

SERAILIZABLE

排队操作,对整个表加锁,一个事务在操作数据时,另一个事务等待。最安全,可以防止脏读、不可重复读、幻读。最安全。,效率最低。

事务传播特性

事务传播特性是指多个事务之间的传播关系。场景为:当一个具有事务的方法,被另一个具有事务的方法调用的时候,需要如何处理事务。

REQUIRED

如果当前没有事务,新建一个事务执行。默认值。

SUPPORTS

如果当前有事务,就在事务中进行。如果当前没有事务,就在非事务的情况下运行。

MANDATORY

必须在事务中执行。如果当前事务,就在事务中执行。如果没有事务,报错。

REQUIRED_NEW

必须在事务中执行。如果当前没有事务,新建一个事务执行。如果当前有事务,把当前事务挂起,则新建一个新的事务执行。能保证这两个事务没有任何关系,如果其中一个事务出现异常而回滚,不会影响另一个事务。

NOT_SOPPORTED

必须在非事务状态执行,如果当前没有事务,正常执行。如果当前有事务,就把当前的事务挂起。

NEVER

必须在非事务状态执行,如果当前没有事务,正常执行。如果当前有事务,报异常。

NESTED

嵌套事务。必须在事务状态下执行,如果没有事务,就新建事务。如果当前有事务,就创建一个嵌套事务执行。嵌套的事务为子事务。子事务和外层事务是有关系的。如果子事务抛异常,不会影响到外层事务,但是外层事务如果抛异常,则子事务也会一起回滚。


标题:整理开发中遇到的所有问题之后台(持续整理中)
作者:阿淼
地址:https://www.mmzsblog.cn/articles/2019/08/08/1565256407388.html

如未加特殊说明,文章均为原创,转载必须注明出处。均采用CC BY-SA 4.0 协议

本网站发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。若本站转载文章遗漏了原文链接,请及时告知,我们将做删除处理!文章观点不代表本网站立场,如需处理请联系首页客服。
• 网站转载须在文章起始位置标注作者及原文连接,否则保留追究法律责任的权利。
• 公众号转载请联系网站首页的微信号申请白名单!

个人微信公众号 ↓↓↓                 

微信搜一搜 Java 学习之道