docker安装nginx并配置通过https访问

📅 2021-11-27 18:19 👁️ 1869 💬 0

关键词:nginx,docker,cannot load certificate,ssl

1. 下载最新的nginx的docker image

$ docker pull nginx:latest

2. 启动nginx容器

运行如下命令来启动nginx container

docker run --detach \
        --name wx-nginx \
        -p 443:443\
        -p 80:80 \
        -v /home/nginx/data:/usr/share/nginx/html:rw\
        -v /home/nginx/config/nginx.conf:/etc/nginx/nginx.conf/:rw\
        -v /home/nginx/config/conf.d/default.conf:/etc/nginx/conf.d/default.conf:rw\
        -v /home/nginx/logs:/var/log/nginx/:rw\
        -v /home/nginx/ssl:/ssl/:rw\
        -d nginx
  • 映射端口443,用于https请求
  • 映射端口80,用于http请求;
  • nginx的默认首页html的存放目录映射到host盘的目录, /home/evan/workspace/wxserver/nginx/data
  • nginx的配置文件映射到host盘的文件,/home/evan/workspace/wxserver/nginx/config/nginx.conf

这里需要准备如下几个文件,

  1. nginx的配置文件
    首先是nginx.conf文件,默认的配置文件如下
#运行nginx的用户
user  nginx;
#启动进程设置成和CPU数量相等
worker_processes  1;

#全局错误日志及PID文件的位置
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

#工作模式及连接数上限
events {
        #单个后台work进程最大并发数设置为1024
    worker_connections  1024;
}


http {
        #设定mime类型
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

        #设定日志格式
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

        #设置连接超时的事件
    keepalive_timeout  65;

        #开启GZIP压缩
    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

可以看到最后一行还要包含另一个配置文件conf.d/default.conf,用来配置server字段

server {
    listen    80;       #侦听80端口,如果强制所有的访问都必须是HTTPs的,这行需要注销掉
    server_name  www.buagengen.com;             #域名

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

        # 定义首页索引目录和名称
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #定义错误提示页面
    #error_page  404              /404.html;

    #重定向错误页面到 /50x.html
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
  1. nginx的默认首页的html文件
    这个html可以自己定义一个,任意的都可以。

这个时候直接通过IP地址就可以访问nginx定义的这个html文件了。但是这个时候的访问只是http的,https的访问还是不行的,需要添加证书到nginx服务器。

3. 通过openssl生成证书

  • 设置server.key,这里需要设置两遍密码:
openssl genrsa -des3 -out server.key 1024 
  • 参数设置,首先这里需要输入之前设置的密码:   
openssl req -new -key server.key -out server.csr

然后需要输入如下的信息,大概填一下就可以了,反正是测试用的

Country Name (2 letter code) [AU]: 国家名称
State or Province Name (full name) [Some-State]: 省
Locality Name (eg, city) []: 城市
Organization Name (eg, company) [Internet Widgits Pty Ltd]: 公司名
Organizational Unit Name (eg, section) []: 
Common Name (e.g. server FQDN or YOUR name) []: 网站域名
Email Address []: 邮箱

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: 这里要求输入密码
An optional company name []:
  • 写RSA秘钥(这里也要求输入之前设置的密码):
openssl rsa -in server.key -out server_nopwd.key
  • 获取私钥:
openssl x509 -req -days 365 -in server.csr -signkey server_nopwd.key -out server.crt

完成这一步之后就得到了我们需要的证书文件和私钥了

  • server.crt
  • server.key

4. 配置nginx服务器,支持https访问

把前面一步生成的文件拷贝到host上的ssl目录,/home/evan/workspace/wxserver/nginx/ssl。
然后修改配置文件default.conf,添加ssl支持

server {
    listen    80;       #侦听80端口,如果强制所有的访问都必须是HTTPs的,这行需要注销掉
    listen    443 ssl;
    server_name  www.buagengen.com;             #域名

    # 增加ssl
    #ssl on;        #如果强制HTTPs访问,这行要打开
    ssl_certificate /ssl/server.crt;
    ssl_certificate_key /ssl/server.key;

    ssl_session_cache    shared:SSL:1m;
    ssl_session_timeout  5m;

     # 指定密码为openssl支持的格式
     ssl_protocols  SSLv2 SSLv3 TLSv1.2;

     ssl_ciphers  HIGH:!aNULL:!MD5;  # 密码加密方式
     ssl_prefer_server_ciphers  on;   # 依赖SSLv3和TLSv1协议的服务器密码将优先于客户端密码

     # 定义首页索引目录和名称
     location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
     }

    #重定向错误页面到 /50x.html
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

重启nginx容器,现在就可以通过https来访问nginx的服务器了。

这里有个重点,证书的目录必须在 /ssl 下面,其他目录启动可能会报找不到在证书的错误!

 

[emerg] 1#1: cannot load certificate "/home/nginx/ssl/1_hxt.yszku.com_bundle.crt": BIO_new_file() failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/home/nginx/ssl/1_hxt.yszku.com_bundle.crt','r') error:2006D080:BIO routines:BIO_new_file:no such file)

 

报上面这个错误 “cannot load certificate”,就把证书移到/ssl目录即可,无论是自己生成的证书,还是阿里云/腾讯云生成的证书.

 

 

阅读更多

SpringBoot开发案例之分布式集群共享Session

📅 2019-08-19 13:55 👁️ 793 💬 0

前言

在分布式系统中,为了提升系统性能,通常会对单体项目进行拆分,分解成多个基于功能的微服务,如果有条件,可能还会对单个微服务进行水平扩展,保证服务高可用。

那么问题来了,如果使用传统管理 Session 的方式,我们会遇到什么样的问题?

案例

这里拿下单举例,用户小明在天猫上相中了一个的娃娃,觉得不错,果断购买,选尺寸,挑身高,然后确认选择,赶紧提交订单,然后就跳转到了登录页面!小明表示很郁闷,大写的问号???

  • 小明进入娃娃页面,此时请求通过代理服务发送到业务系统一。
  • 小明选尺寸,挑身高,此操作并没有对后端服务发送请求。
  • 小明提交订单,此时请求通过代理服务发送到业务系统二,然鹅,二系统此时并没有查询到小明的登录信息,就被无情的跳转到登录页了。

方案

HttpSession 默认使用内存来管理 Session,通常服务端把用户信息存储到各自的 Jvm 内存中。所以小明下单的时候找不到登录信息,那么我么何不把用户信息集中存储!?

为了测试效果,这里我们搭建一个演示案例,项目涉及 SpringBoot、spring-session、redis、nginx 等相关组件。

pom.xml引入依赖:

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置 redis 参数,软件自行安装:

## redis
#session存储类型
spring.session.store-type=redis
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.timeout=3000

简单的用户登录实现,省略部分代码:

@RequestMapping(value="login",method=RequestMethod.POST)
public Result login(String username,String password,HttpServletRequest request,HttpServletResponse response) throws Exception {
        SysUser user = userService.getUser(username);
        if(user==null) {
            return Result.error("用户不存在");
        }else {
            if(user.getPassword().equals(password)) {
                request.getSession().setAttribute("user", user);
                return Result.ok();
            }else {
                return Result.error("密码错误");
            }
        }
}

配置代理实现,基于 Nginx:

server {
        listen       80;
        server_name  blog.52itstyle.vip;
        location / {
            proxy_pass http://192.168.1.2:8080; 
        }
        location /cart {
             proxy_pass http://192.168.1.3:8080$request_uri;
        }
       location /order {
             proxy_pass http://192.168.1.4:8080$request_uri;
        }
  }

配置成功后登录系统,在 redis 中查询用户信息:

127.0.0.1:6379> keys *
1) "spring:session:expirations:1562577660000"
2) "spring:session:sessions:1076c2bd-95b1-4f23-abd4-ab3780e32f6f"
3) "spring:session:sessions:expires:1076c2bd-95b1-4f23-abd4-ab3780e32f6f"

小结

这样,小明就可以开心的买娃娃了!

阅读更多

批量上传本地jar到nexus

📅 2024-07-11 17:55 👁️ 207 💬 0
package com.red.circle.console.adapter.app.tools;

import java.io.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Pattern;


/**
 * 上传依赖到 Maven 私服
 */
public class Deploy {
    /**
     * mvn -s F:\.m2\settings.xml
     * org.apache.maven.plugins:maven-deploy-plugin:2.8.2:deploy-file
     * -Durl=http://IP:PORT/nexus/content/repositories/thirdpart
     * -DrepositoryId=thirdpart
     * -Dfile=antlr-2.7.2.jar
     * -DpomFile=antlr-2.7.2.pom
     * -Dpackaging=jar
     * -DgeneratePom=false
     * -Dsources=./path/to/artifact-name-1.0-sources.jar
     * -Djavadoc=./path/to/artifact-name-1.0-javadoc.jar
     */
    /*public static final String BASE_CMD = "cmd /c mvn " +
            "-s F:\\.m2\\settings.xml " +
            "deploy:deploy-file " +
            "-Durl=http://IP:PORT/nexus/content/repositories/thirdpart " +
            "-DrepositoryId=thirdpart " +
            "-DgeneratePom=false";*/

    public static final String BASE_CMD = "cmd /c mvn " +
            "-s C:\\.m2\\settings.xml " +
            "deploy:deploy-file " +
            "-Durl=http://IP:PORT/repository/maven-releases/ " +
            "-DrepositoryId=maven-releases ";

    public static final Pattern DATE_PATTERN = Pattern.compile("-[\\d]{8}\\.[\\d]{6}-");

    public static final Runtime CMD = Runtime.getRuntime();

    public static final Writer ERROR;

    public static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(10);

    static {
        Writer err = null;
        try {
            err = new OutputStreamWriter(new FileOutputStream("deploy-error.log"), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(0);
        }
        ERROR = err;
    }

    public static void main(String[] args) {
        deploy(new File("C:\\repository").listFiles());
//        if(checkArgs(args)){
//            File file = new File(args[0]);
//            deploy(file.listFiles());
//        }
        EXECUTOR_SERVICE.shutdown();

    }

    public static void error(String error) {
        try {
            System.err.println(error);
            ERROR.write(error + "\n");
            ERROR.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static boolean checkArgs(String[] args) {
        if (args.length != 1) {
            System.out.println("用法如: java -jar Deploy D:\\some\\path\\");
            return false;
        }
        File file = new File(args[0]);
        if (!file.exists()) {
            System.out.println(args[0] + " 目录不存在!");
            return false;
        }
        if (!file.isDirectory()) {
            System.out.println("必须指定为目录!");
            return false;
        }
        return true;
    }

    public static void deploy(File[] files) {
        if (files.length == 0) {
            //ignore
        } else if (files[0].isDirectory()) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deploy(file.listFiles());
                }
            }
        } else if (files[0].isFile()) {
            File pom = null;
            File jar = null;
            File source = null;
            File javadoc = null;
            //忽略日期快照版本,如 xxx-mySql-2.2.6-20170714.095105-1.jar
            for (File file : files) {
                String name = file.getName();
                if (DATE_PATTERN.matcher(name).find()) {
                    //skip
                } else if (name.endsWith(".pom")) {
                    pom = file;
                } else if (name.endsWith("-javadoc.jar")) {
                    javadoc = file;
                } else if (name.endsWith("-sources.jar")) {
                    source = file;
                } else if (name.endsWith(".jar")) {
                    jar = file;
                }
            }
            if (pom != null) {
                if (jar != null) {
                    deploy(pom, jar, source, javadoc);
                } else if (packingIsPom(pom)) {
                    deployPom(pom);
                }
            }
        }
    }

    public static boolean packingIsPom(File pom) {
        BufferedReader reader = null;
        try {
            reader =
                    new BufferedReader(new InputStreamReader(new FileInputStream(pom)));
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.trim().indexOf("<packaging>pom</packaging>") != -1) {
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (Exception e) {
            }
        }
        return false;
    }

    public static void deployPom(final File pom) {
        EXECUTOR_SERVICE.execute(new Runnable() {
            @Override
            public void run() {
                StringBuffer cmd = new StringBuffer(BASE_CMD);
                cmd.append(" -DpomFile=").append(pom.getName());
                cmd.append(" -Dfile=").append(pom.getName());
                try {
                    final Process proc = CMD.exec(cmd.toString(), null, pom.getParentFile());
                    InputStream inputStream = proc.getInputStream();
                    InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
                    BufferedReader reader = new BufferedReader(inputStreamReader);
                    String line;
                    StringBuffer logBuffer = new StringBuffer();
                    logBuffer.append("\n\n\n==================================\n");
                    while ((line = reader.readLine()) != null) {
                        if (line.startsWith("[INFO]") || line.startsWith("Upload")) {
                            logBuffer.append(Thread.currentThread().getName() + " : " + line + "\n");
                        }
                    }
                    System.out.println(logBuffer);
                    int result = proc.waitFor();
                    if (result != 0) {
                        error("上传失败:" + pom.getAbsolutePath());
                    }
                } catch (IOException e) {
                    error("上传失败:" + pom.getAbsolutePath());
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    error("上传失败:" + pom.getAbsolutePath());
                    e.printStackTrace();
                }
            }
        });
    }

    public static void deploy(final File pom, final File jar, final File source, final File javadoc) {
        EXECUTOR_SERVICE.execute(new Runnable() {
            @Override
            public void run() {
                StringBuffer cmd = new StringBuffer(BASE_CMD);
                cmd.append(" -DpomFile=").append(pom.getName());
                if (jar != null) {
                    //当有bundle类型时,下面的配置可以保证上传的jar包后缀为.jar
                    cmd.append(" -Dpackaging=jar -Dfile=").append(jar.getName());
                } else {
                    cmd.append(" -Dfile=").append(jar.getName());
                }
                if (source != null) {
                    cmd.append(" -Dsources=").append(source.getName());
                }
                if (javadoc != null) {
                    cmd.append(" -Djavadoc=").append(javadoc.getName());
                }

                System.out.println(cmd);
                try {
                    final Process proc = CMD.exec(cmd.toString(), null, pom.getParentFile());
                    InputStream inputStream = proc.getInputStream();
                    InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
                    BufferedReader reader = new BufferedReader(inputStreamReader);
                    String line;
                    StringBuffer logBuffer = new StringBuffer();
                    logBuffer.append("\n\n\n=======================================\n");
                    while ((line = reader.readLine()) != null) {
                        if (line.startsWith("[INFO]") || line.startsWith("Upload")) {
                            logBuffer.append(Thread.currentThread().getName() + " : " + line + "\n");
                        }
                    }
                    System.out.println(logBuffer);
                    int result = proc.waitFor();
                    if (result != 0) {
                        error("上传失败:" + pom.getAbsolutePath());
                    }
                } catch (IOException e) {
                    error("上传失败:" + pom.getAbsolutePath());
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    error("上传失败:" + pom.getAbsolutePath());
                    e.printStackTrace();
                }
            }
        });
    }
}

 

阅读更多

工作中Java最常见的6种OOM问题

📅 2024-03-19 09:46 👁️ 1303 💬 0

前言

今天,跟大家一起聊聊线上服务出现OOM问题的6种场景,希望对你会有所帮助。

1 堆内存OOM

堆内存OOM是最常见的OOM了。出现堆内存OOM问题的异常信息如下:

java.lang.OutOfMemoryError: Java heap space

此OOM是由于JVM中heap的最大值,已经不能满足需求了。举个例子:

public class HeapOOMTest {

    public static void main(String[] args) {
        List<HeapOOMTest> list = Lists.newArrayList();
        while (true) {
            list.add(new HeapOOMTest());
        }
    }
}

 

这里创建了一个list集合,在一个死循环中不停往里面添加对象。执行结果:

 出现了java.lang.OutOfMemoryError: Java heap space的堆内存溢出。很多时候,excel一次导出大量的数据,获取在程序中一次性查询的数据太多,都可能会出现这种OOM问题。我们在日常工作中一定要避免这种情况。

2 栈内存OOM

有时候,我们的业务系统创建了太多的线程,可能会导致栈内存OOM。出现堆内存OOM问题的异常信息如下:

java.lang.OutOfMemoryError: unable to create new native thread

给大家举个例子:

public class StackOOMTest {
    public static void main(String[] args) {
        while (true) {
            new Thread().start();
        }
    }
}

使用一个死循环不停创建线程,导致系统产生了大量的线程。执行结果:

如果实际工作中,出现这个问题,一般是由于创建的线程太多,或者设置的单个线程占用内存空间太大导致的。

建议在日常工作中,多用线程池,少自己创建线程,防止出现这个OOM。

 

3 栈内存溢出

我们在业务代码中可能会经常写一些递归调用,如果递归的深度超过了JVM允许的最大深度,可能会出现栈内存溢出问题。出现栈内存溢出问题的异常信息如下:

java.lang.StackOverflowError

例如:

public class StackFlowTest {
    public static void main(String[] args) {
        doSamething();
    }

    private static void doSamething() {
        doSamething();
    }
}

执行结果:

 出现了java.lang.StackOverflowError栈溢出的错误。

我们在写递归代码时,一定要考虑递归深度。即使是使用parentId一层层往上找的逻辑,也最好加一个参数控制递归深度。防止因为数据问题导致无限递归的情况,比如:id和parentId的值相等。

 

4 直接内存OOM

直接内存不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。它来源于NIO,通过存在堆中的DirectByteBuffer操作Native内存,是属于堆外内存,可以直接向系统申请的内存空间。出现直接内存OOM问题时异常信息如下:

java.lang.OutOfMemoryError: Direct buffer memory

例如下面这样的:

public class DirectOOMTest {

    private static final int BUFFER = 1024 * 1024 * 20;

    public static void main(String[] args) {
        ArrayList<ByteBuffer> list = new ArrayList<>();
        int count = 0;
        try {
            while (true) {
                // 使用直接内存
                ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
                list.add(byteBuffer);
                count++;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } finally {
            System.out.println(count);
        }
    }
}

执行结果:

会看到报出来java.lang.OutOfMemoryError: Direct buffer memory直接内存空间不足的异常。

 

5 GC OOM

GC OOM是由于JVM在GC时,对象过多,导致内存溢出,建议调整GC的策略。出现GC OOM问题时异常信息如下:

java.lang.OutOfMemoryError: GC overhead limit exceeded

为了方便测试,我先将idea中的最大和最小堆大小都设置成10M:

-Xmx10m -Xms10m

例如下面这个例子:

public class GCOverheadOOM {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            executor.execute(() -> {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                }
            });
        }
    }
}

执行结果:

出现这个问题是由于JVM在GC的时候,对象太多,就会报这个错误。我们需要改变GC的策略。在老代80%时就是开始GC,并且将-XX:SurvivorRatio(-XX:SurvivorRatio=8)和-XX:NewRatio(-XX:NewRatio=4)设置的更合理。

 

 

6 元空间OOM

JDK8之后使用Metaspace来代替永久代,Metaspace是方法区在HotSpot中的实现。Metaspace不在虚拟机内存中,而是使用本地内存也就是在JDK8中的ClassMetadata,被存储在叫做Metaspace的native memory。出现元空间OOM问题时异常信息如下:

java.lang.OutOfMemoryError: Metaspace

为了方便测试,我修改一下idea中的JVM参数,增加下面的配置:

-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m

指定了元空间和最大元空间都是10M。接下来,看看下面这个例子:

public class MetaspaceOOMTest {
    static class OOM {
    }

    public static void main(String[] args) {
        int i = 0;
        try {
            while (true) {
                i++;
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOM.class);
                enhancer.setUseCache(false);
                enhancer.setCallback(new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        return methodProxy.invokeSuper(o, args);
                    }
                });
                enhancer.create();
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}

执行结果:

 

 程序最后会报java.lang.OutOfMemoryError: Metaspace的元空间OOM。这个问题一般是由于加载到内存中的类太多,或者类的体积太大导致的。

 

这些错误可能日常开发都有遇到过,但是没有去整理。

来源:https://mp.weixin.qq.com/s/Zvj1EoqTODCbkZqTubRWSw

 

阅读更多

Java 遍历文件夹内每个文件夹的文件

📅 2024-03-11 14:58 👁️ 884 💬 0

在Java中,你可以使用java.nio.file包中的FilesDirectoryStream类来遍历文件夹内的所有文件,包括子文件夹中的文件。以下是一个示例代码,展示了如何实现这个功能:

import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;

public class TraverseDirectory {

    public static void main(String[] args) {
        // 指定要遍历的根目录路径
        Path rootPath = Paths.get("path/to/your/root/directory");

        // 遍历根目录下的所有文件和文件夹
        try {
            Files.walk(rootPath)
                  .filter(Files::isRegularFile) // 过滤出普通文件
                  .forEach(path -> {
                      System.out.println(path); // 打印文件路径
                  });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

在这个例子中,Files.walk方法用于遍历给定路径(rootPath)下的所有文件和子目录。filter(Files::isRegularFile)是一个中间操作,它过滤出所有普通文件(即非目录文件)。forEach方法接受一个Lambda表达式,用于对每个文件路径执行操作,这里我们简单地打印出每个文件的路径。

请确保在运行这段代码之前,你已经将"path/to/your/root/directory"替换为你实际想要遍历的目录路径。如果你也想处理目录,可以移除.filter(Files::isRegularFile)这一行,这样就会遍历所有文件和目录。

由于文件操作可能会抛出IOException,所以整个操作被包裹在一个try-catch块中,以便捕获并处理可能发生的异常。

 

阅读更多

Jenkins构建Host key verification failed. lost connection

📅 2023-12-06 14:34 👁️ 87 💬 0
使用jenkins发版,构建时使用了调用shell从jenkins服务器scp jar包到业务服务器。
由于新购买了服务器,并且要将jar包cp到新购买的服务器上,涉及到前任运维交接问题,这块一直没有了解。
 
在jenkins服务器
su jenkins切换到jenkins用户,找到/var/lib/jenkins/.ssh,在jenkins用户中ssh-copy-id拷贝公钥到新购服务器。
 
然后重构,发现已经可以直接拷贝jar包到新购服务器
 
 
 
 
阅读更多

一个由“ YYYY-MM-dd ”引发的惨案

📅 2023-09-26 15:42 👁️ 6 💬 0

在使用一些 App 的时候,竟然被我发现了一个应该是由于前端粗心而导致的 bug,在 2019.12.30 出发,结果 App 上显示的是 2020.12.30(吓得我以为我的订单下错了,此处是不是该把程序员拉去祭天了)。

 

鉴于可能会有程序员因此而被拉去祭天,而我以前学 Java 的时候就有留意过这个问题,所以我还是把这个问题拿出来说一下,希望能尽量避免这方面的粗心大意(毕竟这种问题也很难测出来)。

 
public class DateTest {
 public static void main(String[] args) {
     Calendar calendar = Calendar.getInstance();
     calendar.set(2019, Calendar.AUGUST, 31);
     Date strDate = calendar.getTime();
     DateFormat formatUpperCase = new SimpleDateFormat("yyyy-MM-dd");
     System.out.println("2019-08-31 to yyyy-MM-dd: " + formatUpperCase.format(strDate));
     formatUpperCase = new SimpleDateFormat("YYYY-MM-dd");
     System.out.println("2019-08-31 to YYYY/MM/dd: " + formatUpperCase.format(strDate));
 }
}

我们来看下运行结果:

2019-08-31 to yyyy-MM-dd: 2019-08-31
2019-08-31 to YYYY/MM/dd: 2019-08-31

如果我们日期改成 12.31:

2019-12-31 to yyyy-MM-dd: 2019-12-31
2019-12-31 to YYYY-MM-dd: 2020-12-31

问题就出现了是吧,虽然是一个小小的细节,但是用户看了也会一脸懵,但是我们作为开发者,不能懵啊,赶紧文档查起来:

  • y:year-of-era;正正经经的年,即元旦过后;

  • Y:week-based-year;只要本周跨年,那么这周就算入下一年;就比如说今年(2019-2020) 12.31 这一周是跨年的一周,而 12.31 是周二,那使用 YYYY 的话会显示 2020,使用 yyyy 则会从 1.1 才开始算是 2020。

这虽然是个很小的知识点,但是也有很多人栽到坑里,各位学完可以记录一下咯。我在这里祝愿各位码代码时如有神助,永远没有 bug~

 

转自:redeemer,

链接:juejin.cn/post/7277786940169994303

 

 

阅读更多

spring boot 在Linux下服务启动报错Unable to find Java

📅 2023-09-18 19:16 👁️ 317 💬 0

前言:

  最近在开发项目的过程中遇到了一些坑(也可能不是坑,是自己没弄过导致折腾了很久),我们项目中遇到有用到一些第三方的库,有些第三方库可能不支持openjdk,只支出jdk,所以就要更换一下jdk,然后服务器又是之前的前同事配置的,这时候我把服务器的jdk版本从原来的openjdk1.7换成了官方的jdk1.8之后项目启不起来了,提示  “Unable to find Java” ,????,这个时候问了问chatGPT 它也没给合适的答案,就百度继续找看了一篇文章 说是跟软链接有关,然后一拍脑袋试了试,结果还真是没加软连接,加了之后重启一切正常。

 

正文:

  系统环境:

    Centos 7.5,Jdk1.8

 

  解决办法:

    将java 链接到/sbin 文件夹下

    

ln -s /usr/java/jdk/bin/java /sbin/java

 

然后再重启一切正常,问题解决。

阅读更多

Linux:部署第三方Jar包到Nexus私服

📅 2023-01-31 10:35 👁️ 141 💬 0

为了方便我们开发,经常会有需求就是将第三方的jar包发布到我们自己的nexus私服上;具体可有两种方式实现:1、通过命令进行上传;2、通过nexus管理端页面操作上传。本文就以这两种方式分别做介绍。

mvn install:install-file -DgroupId=com.xxx-DartifactId=xxx.pdf -Dversion=2.1.1 -Dpackaging=jar -Dfile=xxx-2.1.1.jar

mvn install:install-file "-DgroupId=com.xxx" "-DartifactId=xxx.pdf" "-Dversion=2.1.1" "-Dpackaging=jar" "-Dfile=xxx-2.1.1.jar"

mvn deploy:deploy-file "-DgroupId=com.xxx" "-DartifactId=xxx.pdf" "-Dversion=2.1.1" "-Dpackaging=jar" "-Dfile=xxx-2.1.1.jar" -Durl=http://10.188.0.26:8081/repository/maven-releases/ -DrepositoryId=maven-public

DgroupId、DartifactId、Dversion:构成了该jar包在pom.xml的坐标,自己起名字也是可以的.
Dpackaging:表示打包类型.
Dfile:表示需要上传的jar包的绝对路径.
Durl:私服上第三方仓库的地址,打开nexus——>repositories菜单,可以看到该路径。
DrepositoryId:服务器的表示id,就是我们在setting.xml文件中配置的serverId。

https://blog.csdn.net/weixin_37848710/article/details/125915741

 

阅读更多

Linux 简单的Java sh脚本启动jar包

📅 2022-10-08 16:36 👁️ 699 💬 0
 1  2  3 projectName="你的项目名"
 4 
 5 #提醒功能
 6 help() {
 7     echo "help: sh ${projectName}.sh [start|stop|restart]"
 8     exit 1
 9 }
10 
11 #判断项目是否运行,并且返回对应数字(0 为未启动 1为启动)
12 is_exist(){
13     #获取pid的方式,个人喜欢咋写就咋写
14     pid=`ps -ef|grep ${projectName}.jar|grep -v grep|awk '{print $2}'`
15     if [ -z "${pid}" ]
16     then
17         return 0
18     else
19         return 1
20     fi
21 }
22 
23 #开始运行项目
24 start(){
25     is_exist
26     #如果正在运行直接提示
27     if [ $? -eq 1 ]
28     then
29         echo "${projectName} is running"
30         exit 0;
31     else
32         #没有运行则运行项目
33         echo "start running ${projectName} ..."
34         currentPath=`pwd`
35         startPath=$(cd `dirname $0`;pwd)
36         #这里写的比较简单,实际生产环境,需要配置参数
37         cd ${startPath}
38         nohup java -jar -server ${projectName}.jar --spring.profiles.active=test > ${currentPath}/run.log 2>&1 &
39         cd ${currentPath}
40     fi
41 }
42 
43 #停止项目
44 stop(){
45     echo "stop $projectName ..."
46     is_exist
47     if [ $? -eq 1 ]
48     then
49         #通过pid关闭
50         kill -9 $pid
51         echo  "[ok]"
52     else
53         echo  "[ok]"
54     fi
55 }
56 
57 # 选择运行方式
58 case "$1" in
59 start)
60     start
61     ;;
62 stop)
63     stop
64     ;;
65 restart)
66     stop
67     start
68     ;;
69 *)
70     help
71     ;;
72 esac

 

阅读更多

nginx conf 简单配置

📅 2022-10-08 16:27 👁️ 118 💬 0

nginx conf 配置

upstream t****.com {
server localhost:9041;
}

server {
listen 80;
server_name t****.com;#域名
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl;
server_name t****.com; #域名

# 增加ssl
ssl on; #如果强制HTTPs访问,这行要打开
ssl_certificate /home/nginx/ssl/1_t****.com_bundle.crt;
ssl_certificate_key /home/nginx/ssl/2_t****.com.key;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

# 指定密码为openssl支持的格式
ssl_protocols SSLv2 SSLv3 TLSv1.2;

ssl_ciphers HIGH:!aNULL:!MD5; # 密码加密方式
ssl_prefer_server_ciphers on; # 依赖SSLv3和TLSv1协议的服务器密码将优先于客户端密码

# 定义首页索引目录和名称
location ^~ / {
root /home/web/teacher-web/dist;
index index.html;
try_files $uri $uri/ /index.html;
}

location ^~ /api/ {
proxy_pass http://t****.com;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Remote_addr $remote_addr;

rewrite "^/api/(.*)$" /$1 break;
}

#重定向错误页面到 /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}


}

阅读更多

ubuntu 安装最新版 mongodb

📅 2022-09-16 10:57 👁️ 343 💬 0

前言

由于之前ubuntu自动安装的mongodb版本太低,不支持外部查看。

所以需要装最新版

安装最新的官方地址:https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/#uninstall-mongodb-community-edition

 

sudo systemctl restart mongod
sudo systemctl status mongod
cat /var/log/mongodb/mongod.log

 

mkdir -p /data/db#新增数据库
sudo chmod a+w /data/db#给数据库权限

配置文件地址:/etc/mongod.conf

日志文件地址:/var/log/mongodb/mongod.log(可以去配置文件去修改,看看启动日志什么的~~·)

 

如果启动有下面的报错信息:Cannot start server with an unknown storage engine


如果以前装过删除db下所有的文件即可,因为老版本的存储引擎和新版本的存储引擎不一样

----------------------------------------------------------------------------------------------------------------------------------------

2022.10.12更新

数据库被黑客工具了,大无语,要提高安全性

All your data is a backed up. You must pay 0.05 BTC to 12KDdVSHvaB46gGTS7pDiBACyWtx5pv5Hs 48 hours for recover it. After 48 hours expiration we will leaked and exposed all your data. In case of refusal to pay, we will contact the General Data Protection Regulation, GDPR and notify them that you store user data in an open form and is not safe. Under the rules of the law, you face a heavy fine or arrest and your base dump will be dropped from our server! You can buy bitcoin here, does not take much time to buy https://localbitcoins.com or https://buy.moonpay.io/ After paying write to me in the mail with your DB IP: rambler+1jn5p@onionmail.org and/or mariadb@mailnesia.com and you will receive a link to download your database dump.

腾讯云给出的建议:

1)为MongoDB添加认证:MongoDB 启动时添加–auth参数、为MongoDB添加用户认证;

2)MongoDB 自身带有一个HTTP服务和并支持REST接口,在2.6以后这些接口默认是关闭的。MongoDB默认会使用默认端口监听web服务,一般不需要通过web方式进行远程管理,建议禁用。可以修改配置文件设置 nohttpinterface=false

或在启动的时候选择参数 --nohttpinterface。

3)使用云控制台安全组防火墙或本地系统防火墙对访问源IP进行控制,如果仅对内网服务器提供服务,建议勿将 MongoDB服务发布到互联网上。

4)启动时加入参数 --bind_ip 127.0.0.1 或在 /etc/mongodb.conf 文件中添加以下内容:bind_ip = 127.0.0.1,只允许本地访问。

 

 

阅读更多
点击右上角即可分享
微信分享提示