有关软件开发编程知识及学习心得
9月24
解决方法
写入excel时使用 SXSSFWorkbook workbook = new SXSSFWorkbook(xssfWorkbook , 1000);只在内存中留1000行,不会占用过多的内存。下面只贴了部分代码。

public static void createExcelByTrade(List mergeCellConfigList ,  Map cellConfMap , List dataList ,String tempPath , String fileName  ) {
        try {
          int  excelRowNum  = 0;      
          short fontSize = 12;        
          // 创建新的Excel 工作簿
          XSSFWorkbook xssfWorkbook = new XSSFWorkbook();
          SXSSFWorkbook workbook = new SXSSFWorkbook(xssfWorkbook , 1000);
                          
          Sheet sheet = workbook.createSheet(fileName);        
          // 设置合并表头        
          setMergeHeaderCellByTrade(   workbook,   sheet,    mergeCellConfigList ,  excelRowNum,   fontSize );
          excelRowNum ++ ;
          excelRowNum ++ ;
        
          //设置表头
          setHeaderCell(  workbook,   sheet,  cellConfMap ,  excelRowNum,   fontSize );
          excelRowNum ++ ;     //查询数据库中所有的数据  
          setCellData(   workbook,   sheet, cellConfMap,   dataList,   excelRowNum,   fontSize);                        
          // 新建一输出文件流
          FileOutputStream fOut = new FileOutputStream(tempPath);
          // 把相应的Excel 工作簿存盘
          workbook.write(fOut);
          //清空缓冲区数据
          fOut.flush();
          // 操作结束,关闭文件
          fOut.close();
          System.out.println("文件生成...");
        } catch (Exception e) {
            e.printStackTrace();
          System.out.println("已运行 xlCreate() : " + e);
        }
      }

9月1
Word模板引擎,基于Microsoft Word模板和数据生成新的文档,并且支持用户自定义函数,函数可以在Word模板的任何位置执行。

poi-tl是一个完全的Java类库,你可以非常方便的加入到你的Java项目中,核心API只需要一行代码:

XWPFTemplate template = XWPFTemplate.compile("~/file.docx").render(datas);
所有的标签都是以 {{ 开始,以 }} 结束。

{{template}} 文本

{{@template}} 图片

{{#template}} 表格

{{*template}} 列表

{{+template}} Word文档合并

{{?template}}{{/template}} if和foreach功能

示例

从一个超级简单的例子开始:把{{title}}替换成"Poi-tl 模板引擎"。

新建文档template.docx,包含文本{{title}}
TDO模式:Template + data-model = output
//一行代码
XWPFTemplate template = XWPFTemplate.compile("~/template.docx").render(new HashMap(){{
        put("title", "Poi-tl 模板引擎");
}});
template.writeToFile("out_template.docx");

操作手册:http://deepoove.com/poi-tl/
Tags:
9月1
现实企业级Java应用开发、维护中,有时候我们会碰到下面这些问题:

OutOfMemoryError,内存不足

内存泄露

线程死锁

锁争用(Lock Contention)

Java进程消耗CPU过高

......

    这些问题在日常开发、维护中可能被很多人忽视(比如有的人遇到上面的问题只是重启服务器或者调大内存,而不会深究问题根源),但能够理解并解决这些问题是Java程序员进阶的必备要求。本文将对一些常用的JVM性能调优监控工具进行介绍,希望能起抛砖引玉之用。

而且这些监控、调优工具的使用,无论你是运维、开发、测试,都是必须掌握的。

A、 jps(Java Virtual Machine Process Status Tool)      

    jps主要用来输出JVM中运行的进程状态信息。语法格式如下:

jps [options] [hostid]
    如果不指定hostid就默认为当前主机或服务器。

    命令行参数选项说明如下:

-q 不输出类名、Jar名和传入main方法的参数

-m 输出传入main方法的参数

-l 输出main类或Jar的全限名

-v 输出传入JVM的参数
   比如下面:

root@ubuntu:/# jps -m -l
2458 org.artifactory.standalone.main.Main /usr/local/artifactory-2.2.5/etc/jetty.xml
29920 com.sun.tools.hat.Main -port 9998 /tmp/dump.dat
3149 org.apache.catalina.startup.Bootstrap start
30972 sun.tools.jps.Jps -m -l
8247 org.apache.catalina.startup.Bootstrap start
25687 com.sun.tools.hat.Main -port 9999 dump.dat
21711 mrf-center.jar
B、 jstack

    jstack主要用来查看某个Java进程内的线程堆栈信息。语法格式如下:

jstack [option] pid
jstack [option] executable core
jstack [option] [server-id@]remote-hostname-or-ip
    命令行参数选项说明如下:

-l long listings,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况-m mixed mode,不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法)
    jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。下面我们来一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有ps、top、printf、jstack、grep。
Tags: , , , , ,
8月19
最近公司的项目,配置nginx反向代理时遇到一个问题,当设置nginx监听80端口时转发请求没有问题。但一旦设置为监听其他端口,就一直跳转不正常;如访问欢迎页面时应该是重定向到登录页面,在这个重定向的过程中端口丢失了变默认变成80了,当然就访问不到了。
    这里给出一个简短的解决方案,修改nginx的配置文件。
一、配置文件
server {
listen 42112;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host:$server_port; #这里是重点,这样配置才不会丢失端口
location / {
proxy_pass http://127.0.0.1:9001;
}
location = /50x.html {
root html;
}
}

二、产生原因
        nginx没有正确的把端口信息传送到后端,没能正确的配置nginx,下面这行是关键
                proxy_set_header Host $host:$server_port; 这一行是关键。
或者
proxy_set_header Host $http_host;
8月12
在使用idea的过程中,遇到其中一个maven模块变成灰色的故障如下所示:

点击在新窗口中浏览此图片

点开查看项目结构发现,文件没有被正确识别。

解决方法:造成这个的原因可能是忽略了maven模块,可以尝试如下解决方法:在file->setting里,搜索maven,然后选择Ignored Filess,看右边的面板中变灰的maven模块是否处于勾选状态。勾选表示忽略了这个模块的pom文件。取消勾选即可解决。
点击在新窗口中浏览此图片

点击在新窗口中浏览此图片
取消勾选后依旧没有解决可以尝试点击,reimport重新加载依赖。
刚接触IntellijIDEA遇到的问题,我出现此问题的原因是因为以前创建过一个相同名字的模块,因为一些原因删掉了,重新创建同名模块的时候IntellijIDEA直接把我新模块的pom文件设置成了忽略状态。
8月6
今天有个同事说要我帮他看下怎么把这个定时任务的cron表达式放到配置文件里面去,
1、在类上加注解@Component,交给Spring管理
2、在@PropertySource指定配置文件名称,如下配置,指定放在src/main/resource目录下的application.yml文件
3、配置文件application.yml参考内容如下
application.yml

jobs:
  customDictUpdateTime:
    corn: "0/5 * * * * ?"


@Configuration
@Component
@Slf4j
@PropertySource(value = "classpath:application.yml")
public class QuartzTask {

    @Autowired
    private RedisUtil redisUtil;

    private static boolean startTask = true;

    @PostConstruct
    public void startInit() {
        excuteBusiness();
    }

    //定时任务初始化政务宝自定义词库
   //如果获取不到, 取冒号后面的默认值
    @Scheduled(cron = "${jobs.customDictUpdateTime.corn:0/5 * * * * ?}")
    public void excuteTask() {
        excuteBusiness();
    }



上面说的是yml配置文件,有的同学就说了,那么我用的application.properties文件配置呢?

application.properties

jobs.customDictUpdateTime.corn=0/5 * * * *

import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;


@Configuration
@Component
@Slf4j
@PropertySource(value = "classpath:application.properties")
public class QuartzTask {

    @Autowired
    private RedisUtil redisUtil;

    private static boolean startTask = true;

    @PostConstruct
    public void startInit() {
        excuteBusiness();
    }

    //定时任务初始化政务宝自定义词库
   //如果获取不到, 取冒号后面的默认值
    @Scheduled(cron = "${jobs.customDictUpdateTime.corn:0/5 * * * * ?}")
    public void excuteTask() {
        excuteBusiness();
    }



7月2
最近有个项目线上运行的时候客户说你们是不是限制了1M的,我说没有啊,原来发现是nginx报的。
从字面上看,说的是请求的实体太大的问题,那么可以联想到是HTTP请求中的Body大小被限制了的原因。

Nginx中的【client_max_body_size】配置属性

通过查资料,发现是Nginx配置中限制了请求的实体大小,因此就可以通过修改Nginx的配置文件来解决这个问题。Nginx的默认配置文件是conf目录下的nginx.conf文件,如果有自行扩展的配置文件可以在nginx.conf文件中查找include关键字去定位到相应的扩展配置文件。

具体的话是有一个【client_max_body_size】属性,这个属性可以配置在http节点下(http全局),可以配置在server节点下(server全局),也可以配置在location节点下(单应用)。要注意的是,这个属性在不配置的情况下默认值是1m,也就是限制了请求实体的大小为1m。

http节点下:

http {
    # 将Nginx代理的所有请求实体的大小限制为20m
    client_max_body_size 20m;
}
server节点下:

server {
    # 将该服务下的所有请求实体的大小限制为20m
    client_max_body_size 20m;
}
location节点下:

location /yanggb {
    # 将此路由请求的实体大小限制为20m
    client_max_body_size 20m;
}
保存之后要记得重启Nginx使修改后的配置生效。

service nginx restart
Tomcat的【maxPostSize】配置属性

另外的,Tomcat下的conf文件夹中的server.xml文件中也有属性配置【maxPostSize】可以限制post请求参数的大小。


<Connector port="8080" protocol="HTTP/1.1"  
    connectionTimeout="2000"  
    redirectPort="8443"  
    URIEncoding="UTF-8"  
    maxThreads="3000"  
    compression="on" compressableMimeType="text/html,text/xml"  
    maxPostSize="256"/>  
<Connection port="8009" enableLookups="false" redirectPort="8443" debug="0" protocol="AJP/1.3" />

要注意的是,在Tomcat7.0.63之前,maxPostSize属性设置为0和负数都可以代表不限制,但是之后的Tomcat版本只能将maxPostSize属性设置为负数才能代表不限制。
5月28
在开发中如果我们遇到这种需要验证的接口应该怎么调用呢?
这里给出一个Basic Authentication 接口调用的工具示例:
package com.heckjj.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;

import org.apache.commons.codec.binary.Base64;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;


public class GetAPIResultUtil {


    /**
     *
     *
     * @param url
     * @param param
     * @return
     */
    public static String getAPIResult(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            URLConnection conn = realUrl.openConnection();
            //conn.setConnectTimeout(5000);
            String plainCredentials = "heck:12345";
            String base64Credentials = new String(Base64.encodeBase64(plainCredentials.getBytes()));
            conn.setRequestProperty("Authorization", "Basic " + base64Credentials);
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("Content-type", "application/json");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            out = new PrintWriter(conn.getOutputStream());
            out.print(param);
            out.flush();
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
                in.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }
}

至此对基本认证(Basic Authentication)的完整过程就基本实现了,希望对大家有所帮助!
2月18
关于Hutool工具类之HttpUtil如何使用可以参考官方文档Hutool之HttpUtil

其实使用Http和Https使用的方式是一样的。

建议大家可以看看HttpUtil的源码,感觉设计的挺不错的。

导入Maven依赖
<dependency>
   <groupId>cn.hutool</groupId>
   <artifactId>hutool-all</artifactId>
   <version>4.1.0</version>
</dependency>
编写测试类(使用Junit单元测试)

@Test
public void testHttps() throws Exception {
    
    JSONObject json = new JSONObject();
    json.put("username", "1332788xxxxxx");
    json.put("password", "123456.");
    
    String result = HttpRequest.post("https://api.heckjj.com/1/users")
            .header("Content-Type", "application/json")
            .header("X-heck-Application-Id","2f0419a31f9casdfdsf431f6cd297fdd3e28fds4af")
            .header("X-heck-REST-API-Key","1e03efdas82178723afdsafsda4be0f305def6708cc6")
            .body(json)
            .execute().body();
    
    
       System.out.println(result);
            
            
}

方法解释(上面采用的是一种叫链式编程的方式):
header对应的是请求头。
body对应的是请求体(包含参数和参数值)。
HttpRequest里面包含Post、GET、Delete、Put等常用的RestFul方式。

打印如下:

{"createdAt":"2019-04-30 10:42:07","objectId":"6cfdb77081","sessionToken":"269e433440c9e65b8058d016df703ccb"}
2月8
  /*验证IP是否属于某个IP段
   *
   * ipSection    IP段(以'-'分隔)
   * ip           所验证的IP号码
   *
   */
  public static boolean ipExistsInRange(String ip, String ipSection) {
    ipSection = ipSection.trim();
    ip = ip.trim();
    int idx = ipSection.indexOf('-');
    String beginIP = ipSection.substring(0, idx);
    String endIP = ipSection.substring(idx + 1);
    return getIp2long(beginIP) <= getIp2long(ip) && getIp2long(ip) <= getIp2long(endIP);
  }

  public static long getIp2long(String ip) {
    ip = ip.trim();
    String[] ips = ip.split("\\.");
    long ip2long = 0L;
    for (int i = 0; i < 4; ++i) {
      ip2long = ip2long << 8 | Integer.parseInt(ips[i]);
    }

    return ip2long;
  }

  public static long getIp2long2(String ip) {
    ip = ip.trim();
    String[] ips = ip.split("\\.");
    long ip1 = Integer.parseInt(ips[0]);
    long ip2 = Integer.parseInt(ips[1]);
    long ip3 = Integer.parseInt(ips[2]);
    long ip4 = Integer.parseInt(ips[3]);
    long ip2long = 1L * ip1 * 256 * 256 * 256 + ip2 * 256 * 256 + ip3 * 256 + ip4;

    return ip2long;
  }

  public static boolean isIntranetIP(String ip) {
  ipExistsInRange(ip, "172.16.0.0-172.31.255.255") || ip.startsWith("10.");
        //10.10.10.116 是否属于固定格式的IP段10.10.1.00-10.10.255.255

        String ip="10.10.10.116";

        String ipSection="10.10.1.00-10.10.255.255";

        boolean exists=ipExistsInRange(ip,ipSection);

        System.out.println(exists);

        System.out.println(getIp2long(ip));

        System.out.println(getIp2long2(ip));
  }
分页: 1/17 第一页 1 2 3 4 5 6 7 8 9 10 下页 最后页 [ 显示模式: 摘要 | 列表 ]