Spring boot 部署服务

Spring Boot 出来之后,大家都振臂高呼,一些反应慢的还有些摸不着头脑,剩下的一群喷子……算了不说了

就说spring boot 有什么用吧,随着越来越多的人不停的嘲讽Java是如何的落后,如何的缓慢,就像一个老态龙钟的老人,弄的好多从业Javaer人心惶惶,这里还是不扯淡了,有一件事能做好也能做好另一件事,大家都不用纠结了。

先说Spring boot 有什么好处,首先它构建在spring 上,开发建立在spring上面,减少了很多配置,可以自己集成容器启动,这个在业界不停的讨论是否还需要容器来运行程序这个论调上算是Spring帮java扳回一城。

那么接下来就是如何玩了,当你在eclipse+maven的环境中开发完你的微服务,接下来部署开始打jar包,我推荐把依赖copy到单独的文件夹,这样在你的MANIFEST.MF 已经帮你搞定MainClass和classpath的问题,剩下就是自己指定所需要的配置文件位置

一个简单的启动参考: java -jar easyzhxSwap.jar –spring.config.location=/Users/72/Desktop/application.properties

如何优化?你猜?你再猜!

使用jodd发送邮件设置发件人问题

使用odd mail的好处就是不用自己实现各种协议,还可以轻松搞定问题,发送邮件就是一件小事儿了,但是有时候需要设置一下发件人,生的人家都是 各种公司CEO的,到我们这都是 devp@sxnuoyun.com  之类的low掉渣渣。

无奈E文差,网速更差,jodd mail 说的蛮简单,以至于没找见怎么设置发件人字段了,干脆去猜吧,看着哪个像点哪个

Email email = new Email();

email.setFrom(new MailAddress(FROMEMAIL));

65E26EA5-7591-4B7B-B622-50DBD2440DEC

手感不错,猜的蛮准, 使用xxxx <email> 格式自动截取发件人:)

Java常见内存溢出异常分析(OutOfMemoryError)

1.背景知识

1).JVM体系结构

162853_WIxX_820500

2).JVM运行时数据区

162109_yFNI_820500

2.堆溢出(OutOfMemoryError:java heap space)

堆(Heap)是Java存放对象实例的地方。

堆溢出可以分为以下两种情况,这两种情况都会抛出OutOfMemoryError:java heap space异常:

1)内存泄漏

内存泄漏是指对象实例在新建和使用完毕后,仍然被引用,没能被垃圾回收释放,一直积累,直到没有剩余内存可用。

如果内存泄露,我们要找出泄露的对象是怎么被GC ROOT引用起来,然后通过引用链来具体分析泄露的原因。

分析内存泄漏的工具有:Jprofiler,visualvm等。

2)内存溢出

内存溢出是指当我们新建一个实力对象时,实例对象所需占用的内存空间大于堆的可用空间。

如果出现了内存溢出问题,这往往是程序本生需要的内存大于了我们给虚拟机配置的内存,这种情况下,我们可以采用调大-Xmx来解决这种问题。

示例:

package com.demo3;

import java.util.ArrayList;
import java.util.List;

public class OOMTest {

public static void main(String[] args) {
List<byte[]> buffer = new ArrayList<byte[]>();
buffer.add(new byte[10 * 1024 * 1024]);
}
}

通过如下命令运行程序:

java -verbose:gc -Xmn10M -Xms20M -Xmx20M -XX:+PrintGC OOMTest

输出结果:

[GC 836K->568K(19456K), 0.0234380 secs]
[GC 568K->536K(19456K), 0.0009309 secs]
[Full GC 536K->463K(19456K), 0.0085383 secs]
[GC 463K->463K(19456K), 0.0003160 secs]
[Full GC 463K->452K(19456K), 0.0062013 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.demo3.OOMTest.main(OOMTest.java:10)

3.持久带溢出(OutOfMemoryError: PermGen space)

持久带(PermGen space)是JVM实现方法区的地方,因此该异常主要设计到方法区和方法区中的常量池。

1).方法区

方法区(Method Area)不仅包含常量池,而且还保存了所有已加载类的元信息。当加载的类过多,方法区放不下所有已加载的元信息时,就会抛出OutOfMemoryError: PermGen space异常。主要有以下场景:

  • 使用一些应用服务器的热部署的时候,我们就会遇到热部署几次以后发现内存溢出了,这种情况就是因为每次热部署的后,原来的class没有被卸载掉。
  • 如果应用程序本身比较大,涉及的类库比较多,但是我们分配给持久带的内存(通过-XX:PermSize和-XX:MaxPermSize来设置)比较小的时候也可能出现此种问题。

2).常量池

常量池(Runtime Constrant Pool)专门放置源代码中的符号信息。常量池中除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值外,还包含一些以文本形式出现的符号引用,比如:类和接口的全限定名;字段的名称和描述符;方法的名称和描述符等。

当常量池需要的空间大于常量池的实际空间时,也会抛出OutOfMemoryError: PermGen space异常。

例如,Java中字符串常量是放在常量池中的,String.intern()这个方法运行的时候,会检查常量池中是否存和本字符串相等的对象,如果存在直接返回对常量池中对象的引用,不存在的话,先把此字符串加入常量池,然后再返回字符串的引用。那么可以通过String.intern方法来模拟一下运行时常量区的溢出.

示例:

package com.demo3;
 
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
 
public class OOMTest {
 
    public static void main(String[] args) {
        List list = new ArrayList();
        while (true) {
            list.add(UUID.randomUUID().toString().intern());
        }
    }
}

通过以下命令运行:

java -verbose:gc -Xmn5M -Xms10M -Xmx10M -XX:MaxPermSize=1M -XX:+PrintGC OOMTest

最后的运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
        at java.lang.String.intern(Native Method)
        at OOMTest.main(OOMTest.java:8)

4.线程栈

栈(JVM Stack)存放主要是栈帧( 局部变量表, 操作数栈 , 动态链接 , 方法出口信息 )的地方。注意区分栈和栈帧:栈里包含栈帧。

与线程栈相关的内存异常有两个:

  • StackOverflowError(方法调用层次太深,内存不够新建栈帧)
  • OutOfMemoryError(线程太多,内存不够新建线程)

1).java.lang.StackOverflowError

栈溢出抛出java.lang.StackOverflowError错误,出现此种情况是因为方法运行的时候,请求新建栈帧时,栈所剩空间小于战帧所需空间。

例如,通过递归调用方法,不停的产生栈帧,一直把栈空间堆满,直到抛出异常 :

package com.demo3;
 
public class OOMTest {
    public void stackOverFlowMethod() {
        stackOverFlowMethod();
    }
 
    public static void main(String... args) {
        OOMTest oom = new OOMTest();
        oom.stackOverFlowMethod();
    }
}

运行结果:

Exception in thread "main" java.lang.StackOverflowError
    at com.demo3.OOMTest.stackOverFlowMethod(OOMTest.java:5)
    at com.demo3.OOMTest.stackOverFlowMethod(OOMTest.java:5)
    at com.demo3.OOMTest.stackOverFlowMethod(OOMTest.java:5)
    at com.demo3.OOMTest.stackOverFlowMethod(OOMTest.java:5)
    at com.demo3.OOMTest.stackOverFlowMethod(OOMTest.java:5)
    at com.demo3.OOMTest.stackOverFlowMethod(OOMTest.java:5)
    at com.demo3.OOMTest.stackOverFlowMethod(OOMTest.java:5)
    at com.demo3.OOMTest.stackOverFlowMethod(OOMTest.java:5)
    .....

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

因为虚拟机会提供一些参数来保证堆以及方法区的分配,剩下的内存基本都由栈来占有,而且每个线程都有自己独立的栈空间(堆,方法区为线程共有)。所以:

  • 如果你把虚拟机参数Xss调大了,每个线程的占用的栈空间也就变大了,那么可以建立的线程数量必然减少
  • 公式:线程栈总可用内存=JVM总内存-(-Xmx的值)- (-XX:MaxPermSize的值)- 程序计数器占用的内存

如果-Xmx或者-XX:MaxPermSize太大,那么留给线程栈可用的空间就越小,在-Xss参数配置的栈容量不变的情况下,可以创建的线程数也就越小。

上述两种情况都会导致:当创建的线程数太多时,栈内存不够用来创建新的线程,那么就会抛出java.lang.OutOfMemoryError:unable to create new native thread 异常。

PS:由于在window平台的虚拟机中,java的线程是隐射到操作系统的内核线程上的,所以运行一下产生该异常的代码时,可能会导致操作系统假死。

 

[FROM:http://my.oschina.net/sunchp/blog/369412]

Java 程序员在写 SQL 程序时候常犯的 10 个错误

Java程序员编程时需要混合面向对象思维和一般命令式编程的方法,能否完美的将两者结合起来完全得依靠编程人员的水准:

  • 技能(任何人都能容易学会命令式编程)
  • 模式(有些人用“模式-模式”,举个例子,模式可以应用到任何地方,而且都可以归为某一类模式)
  • 心境(首先,要写个好的面向对象程序是比命令式程序难的多,你得花费一些功夫)

但当Java程序员写SQL语句时,一切都不一样了。SQL是说明性语言而非面向对象或是命令式编程语言。在SQL中要写个查询语句是很简单的。但在Java里类似的语句却不容易,因为程序员不仅要反复考虑编程范式,而且也要考虑算法的问题。

下面是Java程序员在写SQL时常犯的错误(没有特定的顺序):

1.忘掉NULL

Java程序员写SQL时对NULL的误解可能是最大的错误。也许是因为(并非唯一理由)NULL也称作UNKNOWN。如果被称作UNKNOWN,这还好理解些。另一个原因是,当你从数据库拿东西或是绑定变量时,JDBC将SQL NULL 和Java中的null对应了起来。这样导致了NULL = NULL(SQL)和null=null(Java)的误解。

对于NULL最大的误解是当NULL被用作行值表达式完整性约束条件时。

另一个误解出现在对于NULL 在 NOT IN anti-joins的应用中。

解决方法:

好好的训练你自己。当你写SQL时要不停得想到NULL的用法:

  • 这个NULL完整性约束条件是正确的?
  • NULL是否影响到结果?

2.在Java内存中处理数据

很少有Java开发者能将SQL理解的很好.偶尔使用的JOIN,还有古怪的UNION,好吧.但是对于窗口函数呢?还有对集合进行分组呢?许多的Java开发者将SQL数据加载到内存中,将这些数据转换成某些相近的集合类型,然后再那些集合上面使用边界循环控制结构(至少在Java8的集合升级以前)执行令人生厌的数学运算.

但是一些SQL数据库支持先进的(而且是SQL标准支持的!)OLAP特性,这一特性表现更好而且写起来也更加方便.一个(并不怎么标准的)例子就是Oracle超棒的MODEL分句.只让数据库来做处理然后只把结果带到Java内存中吧.因为毕竟所有非常聪明的家伙已经对这些昂贵的产品进行了优化.因此实际上,通过将OLAP移到数据库,你将获得一下两项好处:

  • 便利性.这比在Java中编写正确的SQL可能更加的容易.
  • 性能表现.数据库应该比你的算法处理起来更加快.而且更加重要的是,你不必再去传递数百万条记录了.

完善的方法:

每次你使用Java实现一个以数据为中心的算法时,问问自己:有没有一种方法可以让数据库代替为我做这种麻烦事.

3. 使用UNION代替UNION ALL

太可耻了,和UNION相比UNION ALL还需要额外的关键字。如果SQL标准已经规定了支持,那么可能会更好点。

  • UNION(允许重复)
  • UNION DISTINCT (去除了重复)

移除重复行不仅很少需要(有时甚至是错的),而且对于带很多行的大数据集合会相当慢,因为两个子select需要排序,而且每个元组也需要和它的子序列元组比较。

注意即使SQL标准规定了INTERSECT ALL和EXCEPT ALL,很少数据库会实现这些没用的集合操作符。

处理方法:
每次你写UNION语句时,考虑实际上是否需要UNION ALL语句。

4.通过JDBC分页技术给大量的结果进行分页操作

大部分的数据库都会支持一些分页命令实现分页效果,譬如LIMIT..OFFSET,TOP..START AT,OFFSET..FETCH语句等。即使没有支持这些语句的数据库,仍有可能对ROWNUM(甲骨文)或者是ROW NUMBER() OVER()过滤(DB2,SQL Server2008等),这些比在内存中实现分页更快速。在处理大量数据中,效果尤其明显。

纠正:

仅仅使用这些语句,那么一个工具(例如JOOQ)就可以模拟这些语句的操作。

5.在java内存中加入数据

从SQL的初期开始,当在SQL中使用JOIN语句时,一些开发者仍旧有不安的感觉。这是源自对加入JOIN后会变慢的固有恐惧。假如基于成本的优化选择去实现嵌套循环,在创建一张连接表源前,可能加载所有的表在数据库内存中,这可能是真的。但是这事发生的概率太低了。通过合适的预测,约束和索引,合并连接和哈希连接的操作都是相当的快。这完全是是关于正确元数据(在这里我不能够引用Tom Kyte的太多)。而且,可能仍然有不少的Java开发人员加载两张表通过分开查询到一个映射中,并且在某种程度上把他们加到了内存当中。

纠正:

假如你在各个步骤中有从各种表的查询操作,好好想想是否可以表达你的查询操作在单条语句中。

6.使用DISTINCT和UNION从一个偶然的笛卡尔积中删除重复

由于重量级连接的使用,一个人可以松绑对在SQL语句中起作用的所有关系的跟踪.具体来说,如果多列外键关系被加入进来的话,忘掉加入使用JOIN…ON分句的相关谓语是很有可能的。这可能会导致重复的记录,但也可能只发生在异常的情况下。一些开发者可能因此选择使用DISTINCT来移除那些重复的记录。这在三个方面都证明是错误的:

它(可能)能够治标,但并不治本。极端情况下它也可能练治标的能力也没有。

对于含有许多列的大型结果集,它的处理是缓慢的。DISTINCT执行了一个ORDER BY 的操作来移除重复的记录。

对于大型的笛卡尔积,它的处理是缓慢的,仍将会把许多的数据加载到内存中。

解决方法:

作为首要的规则,当你得到了不想要的重复记录时,常常要重新检查检查你的JOIN谓语。很可能有一个微妙的笛卡尔积在那某一个地方。

7.不去使用MERGE语句

这并不是一个真正的错误,但可能是由于某些知识的缺失,或者是对于强大的MERGE语句的某种畏惧。一些数据库知道其他形式的UPSERT语句,例如,MYSQL的 ON DUPLICATE KEY UPDATE 分句。但是MERGE真的是如此强大,在大多数重视扩展SQL标准的数据库,如SQL Server中是很重要的。

解决方法:

如果你正在通过链接INERT和UPDATE,或者通过链接SELECT…FOR UPDATE进行UPSERT,然后进行INSERT或者UPDATE,请三思。在冒此风险之外,你还可以选择使用一个简单的MERGE语句进行表达。

8. 使用聚合函数代替窗口函数(window functions)

在介绍窗口函数之前,在SQL中聚合数据意味着使用GROUP BY语句与聚合函数相映射。在很多情形下都工作得很好,如聚合数据需要浓缩常规数据,那么就在join子查询中使用group查询。

但是在SQL:2003中定义了窗口函数,这个在很多主流数据库都实现了它。窗口函数能够在结果集上聚合数据,但是却没有分组。事实上,每个窗口函数都有自己的、独立的PARTITION BY语句,这个工具对于显示报告太TM好了。

使用窗口函数:

  • 使SQL更易读(但在子查询中没有GROUP BY语句专业)
  • 提升性能,像关系数据库管理系统能够更容易优化窗口函数

解决方法:

当你在子查询中使用GROUP BY语句时,请再三考虑是否可以使用窗口函数完成。

9. 使用内存间接排序

SQL的ORDER BY语句支持很多类型的表达式,包括CASE语句,对于间接排序十分有用。你可能重来不会在Java内存中排序数据,因为你会想:

  • SQL排序很慢
  • SQL排序办不到

处理方法:

如果你在内存中排序任何SQL数据,请再三考虑,是否不能在数据库中排序。这对于数据库分页数据十分有用。

10. 一条一条的插入大量纪录

JDBC ”懂“批处理(batch),你应该不会忘了它。不要使用INSERT语句来一条一条的出入成千上万的记录,(因为)每次都会创建一个新的PreparedStatement对象。如果你的所有记录都插入到同一个表时,那么就创建一个带有一条SQL语句以及附带很多值集合的插入批处理语句。你可能需要在达到一定量的插入记录后才提交来保证UNDO日志瘦小,这依赖于你的数据库和数据库设置。

处理方法:
总是使用批处理插入大量数据。

J2EE平台升级备忘录

从事IT开发,难免会遇到升级维护的时候,往往也是这个时候最容易出现问题。

之前的上家公司不知道是谁定下的条文,升级的时候只升级修改的class文件,其他没有改动的文件不做修改。

其实在升级的过程中发生了很多的意外,研发莫名其妙,运维更是摸不着头脑。

这里举一个简单的例子:

Config.java

Config

 

Test.java

Test

 

运行Test.java 会打印什么结果呢?

Hello

 

没错,我们如果部署到环境中也是如此,cmd下输出结果

Hello1

 

以上也许你在生产环境中没有任何的问题,那么我们修改一下Config类呢?
don't

然后在eclipse中执行Test文件,结果肯定也应该是预想的效果:

Don't1

 

so right,如果此时我们需要升级了,按照修改哪个替换哪个的理论,那么我们只需要替换Config文件就行了,但是如果这样就升级完成了的话,

那么在cmd下会是什么效果呢?

Ok  let’s go 》》》》

say1

 

发现问题没有,是不是预想的效果变了?那么所谓的修改哪里替换哪里的行为方式这个时候就失效了呢?

如果全量替换呢?

say2

这才是你想要的结果吧。

那么以后该如何升级呢?是不是打成war包会perfect呢?那么之前的同事,我们是不是无缘无故的浪费了很多回家睡觉的时间呢?

 

java 获取时间起止工具类

This is shared by Internet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
package org.uninf.time;
 
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
 
public class DateUtils {
	public static String[] getBegainAndEndTime(Date date, String mode) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		Date[] dates = getBegainAndEndDate(date, mode);
		return new String[] { format.format(dates[0]), format.format(dates[1]) };
	}
 
	public static Date[] getBegainAndEndDate(Date date, String mode) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		Date begin = new Date();
		Date end = new Date();
		if (mode == null || mode.equalsIgnoreCase("日")
				|| mode.equalsIgnoreCase("day")) {
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			calendar.set(Calendar.MILLISECOND, 0);
			begin = calendar.getTime();
			calendar.set(Calendar.HOUR_OF_DAY, 23);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			calendar.set(Calendar.MILLISECOND, 999);
			end = calendar.getTime();
		} else if (mode.equalsIgnoreCase("周") || mode.equalsIgnoreCase("week")) {
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			calendar.set(Calendar.MILLISECOND, 0);
			begin = calendar.getTime();
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
			calendar.add(Calendar.DAY_OF_WEEK, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 23);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			calendar.set(Calendar.MILLISECOND, 999);
			end = calendar.getTime();
		} else if (mode.equalsIgnoreCase("月") || mode.equalsIgnoreCase("month")
				|| mode.equalsIgnoreCase("0")) {
			calendar.set(Calendar.DAY_OF_MONTH, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			calendar.set(Calendar.MILLISECOND, 0);
			begin = calendar.getTime();
			calendar.set(Calendar.DAY_OF_MONTH,
					calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
			calendar.set(Calendar.HOUR_OF_DAY, 23);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			calendar.set(Calendar.MILLISECOND, 999);
			end = calendar.getTime();
		} else if (mode.equalsIgnoreCase("季")
				|| mode.equalsIgnoreCase("season")) {
			int month = calendar.get(Calendar.MONTH) + 1;
			if (month % 3 == 0) {// 季度结束月 6(3,4,5)
				calendar.set(Calendar.MONTH, month - 3);
				calendar.set(Calendar.DAY_OF_MONTH, 1);
				calendar.set(Calendar.HOUR_OF_DAY, 0);
				calendar.set(Calendar.MINUTE, 0);
				calendar.set(Calendar.SECOND, 0);
				calendar.set(Calendar.MILLISECOND, 0);
				begin = calendar.getTime();
				calendar.set(Calendar.MONTH, month - 1);
				calendar.set(Calendar.DAY_OF_MONTH,
						calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
				calendar.set(Calendar.HOUR_OF_DAY, 23);
				calendar.set(Calendar.MINUTE, 59);
				calendar.set(Calendar.SECOND, 59);
				calendar.set(Calendar.MILLISECOND, 999);
				end = calendar.getTime();
			} else if (month % 3 == 1) {// 季度起始月 4(3,4,5)
				calendar.set(Calendar.MONTH, month - 1);
				calendar.set(Calendar.DAY_OF_MONTH, 1);
				calendar.set(Calendar.HOUR_OF_DAY, 0);
				calendar.set(Calendar.MINUTE, 0);
				calendar.set(Calendar.SECOND, 0);
				calendar.set(Calendar.MILLISECOND, 0);
				begin = calendar.getTime();
				calendar.set(Calendar.MONTH, month + 1);
				calendar.set(Calendar.DAY_OF_MONTH,
						calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
				calendar.set(Calendar.HOUR_OF_DAY, 23);
				calendar.set(Calendar.MINUTE, 59);
				calendar.set(Calendar.SECOND, 59);
				calendar.set(Calendar.MILLISECOND, 999);
				end = calendar.getTime();
			} else if (month % 3 == 2) {// 季度中间月 5(3,4,5)
				calendar.set(Calendar.MONTH, month - 2);
				calendar.set(Calendar.DAY_OF_MONTH, 1);
				calendar.set(Calendar.HOUR_OF_DAY, 0);
				calendar.set(Calendar.MINUTE, 0);
				calendar.set(Calendar.SECOND, 0);
				calendar.set(Calendar.MILLISECOND, 0);
				begin = calendar.getTime();
				calendar.set(Calendar.MONTH, month);
				calendar.set(Calendar.DAY_OF_MONTH,
						calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
				calendar.set(Calendar.HOUR_OF_DAY, 23);
				calendar.set(Calendar.MINUTE, 59);
				calendar.set(Calendar.SECOND, 59);
				calendar.set(Calendar.MILLISECOND, 999);
				end = calendar.getTime();
			}
		} else if (mode.equalsIgnoreCase("年") || mode.equalsIgnoreCase("year")
				|| mode.equalsIgnoreCase("1")) {
			calendar.set(Calendar.DAY_OF_YEAR, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			calendar.set(Calendar.MILLISECOND, 0);
			begin = calendar.getTime();
			calendar.set(Calendar.DAY_OF_YEAR,
					calendar.getActualMaximum(Calendar.DAY_OF_YEAR));
			calendar.set(Calendar.HOUR_OF_DAY, 23);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			calendar.set(Calendar.MILLISECOND, 999);
			end = calendar.getTime();
		}
 
		return new Date[] { begin, end };
	}
 
	public static String format(Date date) {
		String result = "";
		SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
		result = format.format(date);
		return result;
	}
 
	public static String format(Date date, String pattern) {
		String result = "";
		if (null == pattern) {
			pattern = "yyyy-MM-dd HH:mm:ss";
		}
		if (date == null) {
			date = new Date();
			date.setTime(0);
		}
 
		SimpleDateFormat format = new SimpleDateFormat(pattern);
		result = format.format(date);
		return result;
	}
 
	public static Date parse(String str) {
		Date date = null;
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		try {
			date = format.parse(str);
		} catch (ParseException e) {
			e.printStackTrace();
		}
 
		return date;
 
	}
 
	public static String format(String str) {
		Date date = parse(str);
		String result = "";
		result = format(date);
 
		return result;
	}
 
	public static Date changeDate(Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String newDateStr = sdf.format(date) + " 17:00:00";
		return getStringToDate(newDateStr);
	}
 
	public static String parse(Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String newDateStr = sdf.format(date);
		return sdf.format(date);
	}
 
	// public static String changeDate(Date date) {
	// SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
	// String newDateStr = sdf.format(date)+" 17:00:00";
	// return newDateStr;
	// }
	public static Date getStringToDate(String s) {
 
		Timestamp ts = Timestamp.valueOf(s);
		return ts;
	}
 
	public static void main(String[] args) {
		String[] dates = getBegainAndEndTime(new Date(), "");
		System.out.println(dates[0] + " ~ " + dates[1]);
	}
}

基于jersey打造你的restful风格的java Web 服务

使用注解来让你的POJO完成restful风格的服务。

本demo基于jersry1.2

提供的服务类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.uninf.webprovider.action;
 
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tmsps.paladin.utils.iptools.IPUtil;
 
@Path(value = "/IPService")
public class IPAction {
	public final static Logger log = LoggerFactory.getLogger(IPAction.class);
 
	@GET
	@Path(value = "/location/{ip}")
	@Produces("text/plain;charset=UTF-8")
	public String getLocationByIP(@PathParam("ip") String ip) {
		log.info("{" + ip + "} request get location service");
		return IPUtil.getAddrByIP(IPUtil.getServerIP(ip));
	}
 
}

web.xml的配置

1
2
3
4
5
6
7
8
<servlet>
		<servlet-name>Jersey Web Application</servlet-name>
		<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>Jersey Web Application</servlet-name>
		<url-pattern>/restful/*</url-pattern>
	</servlet-mapping>

and then you can vis http://localhost:8080/yourproject/restful/IPService/location/baidu.com

访问查看页面效果
baidu

Java文件复制操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package org.uninf.ffmpeg;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
/**
 * 文件操作类
 * 
 * @author zhangwei
 * 
 * 
 * @time 2013-2-17 上午9:35:50
 * 
 */
public class FileTools {
	static Logger log = LoggerFactory.getLogger(FileTools.class);
 
	/**
	 * 文件复制工具类
	 * 
	 * @param sourceFile
	 * @param targetFile
	 */
	public static final boolean copyFile(String sourceFile, String destFile) {
		long st = System.nanoTime();
		File sf = new File(sourceFile);
		File df = new File(destFile);
		FileChannel fcin = null;
		FileChannel fcout = null;
		try {
			fcin = new FileInputStream(sf).getChannel();
			fcout = new FileOutputStream(df).getChannel();
			fcin.transferTo(0, fcin.size(), fcout);
		} catch (IOException e) {
			log.error(e.getMessage());
			return false;
		} finally {
			try {
				fcin.close();
				fcout.close();
			} catch (IOException e) {
				log.error(e.getMessage());
				return false;
			}
			System.err.println(System.nanoTime() - st);
		}
		return true;
	}
 
	public static final boolean copyFile2(String sourceFile, String destFile) {
		long st = System.nanoTime();
		File sf = new File(sourceFile);
		File df = new File(destFile);
		FileInputStream fin = null;
		FileOutputStream fout = null;
		FileChannel fcin = null;
		FileChannel fcout = null;
		ByteBuffer bb = null;
		long bbSize = 1024 * 1024 * 2;// 缓冲区大小 2M
		try {
			fin = new FileInputStream(sf);
			fout = new FileOutputStream(df);
			fcin = fin.getChannel();
			fcout = fout.getChannel();
			while (true) {
				if (fcin.position() == fcout.size()) {// #复制完毕
					break;
				}
				if (fcin.size() - fcout.position() < bbSize) {
					bbSize = fcin.size() - fcout.position();
				}
				bb = ByteBuffer.allocate((int) bbSize);
				fcin.read(bb);
				bb.flip();
				fcout.write(bb);
				fcout.force(false);
			}
		} catch (Exception e) {
			log.error(e.getMessage());
			return false;
		} finally {
			try {
				fcin.close();
				fcout.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			System.err.println(System.nanoTime() - st);
		}
		return true;
	}
 
	/**
	 * 移动文件
	 * 
	 * @param sourceFile
	 * @param destFile
	 * @return
	 */
	public static boolean removeFile(String sourceFile, String destFile) {
		File source = new File(sourceFile);
		File dest = new File(destFile);
		return source.renameTo(dest);
	}
 
	public static void main(String[] args) {
		FileTools.copyFile2("d:/Tools/jdk-7u10-linux-x64.rpm",
				"e:/jdk-7u10-linux-x64.rpm");
	}
}

C#的3DES加解密Java版

这两天做项目需要和.net 平台做通信,他们使用的加密是3DES,互联网上比较常见的一些算法,J2EE平台无法公用,只有自己写一个,给有需要的朋友一个参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
package com.uninf.video.util.encryption;
 
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
 
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
 
/**
 * 3DES 加密解密算法,用于拓荒族通信 http://www.tuohuangzu.com
 * 
 * @author zhangwei
 * 
 * 
 * @time 2013-1-29 上午8:53:23
 * 
 */
public class DES3Tools {
	Logger log = LoggerFactory.getLogger(DES3Tools.class);
 
	byte[] encryptKey;
	DESedeKeySpec spec;
	SecretKeyFactory keyFactory;
	SecretKey theKey;
	Cipher cipher;
	IvParameterSpec IvParameters;
 
	/**
	 * 字符串转换为byte数组
	 * 
	 * @param str
	 * @return
	 */
	public byte[] StringToByte(String str) {
		char[] ch = str.toUpperCase().toCharArray();
		byte[] newBytes = new byte[str.length() / 2];
		for (int i = 0; i < newBytes.length; i++) {
			newBytes[i] = (byte) (Char2Hex(ch[i * 2]) * (0x10) + Char2Hex(ch[i * 2 + 1]));
		}
		return newBytes;
	}
 
	/**
	 * 字符与16进制转换
	 * 
	 * @param chr
	 * @return
	 */
	private byte Char2Hex(char chr) {
		switch (chr) {
		case '0':
			return 0x00;
		case '1':
			return 0x01;
		case '2':
			return 0x02;
		case '3':
			return 0x03;
		case '4':
			return 0x04;
		case '5':
			return 0x05;
		case '6':
			return 0x06;
		case '7':
			return 0x07;
		case '8':
			return 0x08;
		case '9':
			return 0x09;
		case 'A':
			return 0x0a;
		case 'B':
			return 0x0b;
		case 'C':
			return 0x0c;
		case 'D':
			return 0x0d;
		case 'E':
			return 0x0e;
		case 'F':
			return 0x0f;
		}
		return 0x00;
	}
 
	/**
	 * 初始化3des加密工具类
	 */
	public DES3Tools() {
		try {
			// 检测是否有 TripleDES 加密的供应程序
			// 如无,明确地安装SunJCE 供应程序
			try {
				cipher = Cipher.getInstance("DESede");
			} catch (Exception e) {
				log.error("Installling SunJCE provider.");
				Provider sunjce = new com.sun.crypto.provider.SunJCE();
				Security.addProvider(sunjce);
			}
			// 创建一个密钥 24位以上的Key
			encryptKey = StringToByte(EncryptConfig.DES3_KEY);
			// 为上一密钥创建一个指定的 DESSede key
			spec = new DESedeKeySpec(encryptKey);
			// 得到 DESSede keys
			keyFactory = SecretKeyFactory.getInstance("DESede");
			// 生成一个 DESede 密钥对象
			theKey = keyFactory.generateSecret(spec);
 
			// 创建一个 DESede 密码
			cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
 
			// 为 CBC 模式创建一个用于初始化的 vector 对象
			IvParameters = new IvParameterSpec(
					StringToByte(EncryptConfig.DES3_IV));
		} catch (Exception exc) {
			// 记录加密或解密操作错误
			log.error("Constructor error :" + exc.getMessage());
		}
	}
 
	/**
	 * 加密算法
	 * 
	 * @param arg
	 *            等待加密的密码
	 * @return 加密以后的密码
	 * @throws Exception
	 */
	public byte[] encrypt(String arg) {
		String encrypted_args = null;
		byte[] encrypted_argb = null;
 
		try {
			// 以加密模式初始化密钥
			cipher.init(Cipher.ENCRYPT_MODE, theKey, IvParameters);
			// 加密前的密码(旧)
			byte[] plainttext = arg.getBytes();
			// 加密密码
			encrypted_argb = cipher.doFinal(plainttext);
			// 转成字符串,得到加密后的密码(新)
			encrypted_args = new String(encrypted_argb);
		} catch (Exception ex) {
			// 记录加密错误
			log.error("encrypt error : " + ex.getMessage());
		}
		return encrypted_argb;
	}
 
	/**
	 * 解密算法
	 * 
	 * @param argb
	 *            加过密的密码
	 * @return 解密后的密码
	 */
	public String decrypt(byte[] argb) {
		String decrypted_args = null;
		try {
			// 以解密模式初始化密钥
			cipher.init(Cipher.DECRYPT_MODE, theKey, IvParameters);
			// 构造解密前的密码
			byte[] decryptedPassword = argb;
			// 解密密码
			byte[] decrypted_pwd = cipher.doFinal(decryptedPassword);
			// 得到结果
			decrypted_args = new String(decrypted_pwd);
		} catch (Exception ex) {
			// 记录解密错误
		}
		return decrypted_args;
	}
 
	/**
	 * byte 数组返回字符串
	 * 
	 * @param arrB
	 * @return
	 */
	public String byteArr2HexStr(byte[] arrB) {
		int iLen = arrB.length;
		// 每个byte用两个字符才能表示,所以字符串的长度是数组长度的两倍
		StringBuffer sb = new StringBuffer(iLen * 2);
		for (int i = 0; i < iLen; i++) {
			int intTmp = arrB[i];
			// 把负数转换为正数
			while (intTmp < 0) {
				intTmp = intTmp + 256;
			}
			// 小于0F的数需要在前面补0
			if (intTmp < 16) {
				sb.append("0");
			}
			sb.append(Integer.toString(intTmp, 16));
		}
		return sb.toString();
	}
 
	/**
	 * 字符串转换byte数组
	 * 
	 * @param strIn
	 * @return
	 */
	public byte[] hexStr2ByteArr(String strIn) {
		byte[] arrB = strIn.getBytes();
		int iLen = arrB.length;
		// 两个字符表示一个字节,所以字节数组长度是字符串长度除以2
		byte[] arrOut = new byte[iLen / 2];
		for (int i = 0; i < iLen; i = i + 2) {
			String strTmp = new String(arrB, i, 2);
			arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
		}
		return arrOut;
	}
 
	/**
	 * base64 加密
	 * 
	 * @param argb
	 * @return
	 */
	public String base64Encode(byte[] argb) {
		return new BASE64Encoder().encode(argb);
	}
 
	/**
	 * base64 解密
	 * 
	 * @param args
	 * @return
	 * @throws IOException
	 */
	public byte[] base64DEcode(String args) {
		byte[] bytes = null;
		try {
			bytes = new BASE64Decoder().decodeBuffer(args);
		} catch (IOException e) {
			log.error("base64decoder error :" + e.getMessage());
		}
		return bytes;
	}
 
	/**
	 * 生成验证字符串
	 * 
	 * @param args
	 * @return
	 */
	public String getGarbleString(String args) {
		byte[] plainText = null;
		try {
			plainText = args.getBytes("UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		MessageDigest messageDigest = null;
		try {
			messageDigest = MessageDigest.getInstance("SHA-1");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		messageDigest.update(plainText);
		byte[] digest = messageDigest.digest();
		String newStr = base64Encode(digest);
		return newStr;
	}
 
	/**
	 * 验证字符串
	 * 
	 * @return
	 */
	public boolean verifyString(String[] args) {
		if (args.length != 2) {
			return false;
		} else {
			return getGarbleString(args[0]).equals(args[1]);
		}
	}
 
	/**
	 * 3des 通信最终加密工具
	 * 
	 * @param plainText
	 * @return
	 */
	public static final String finalEncode(String plainText) {
		DES3Tools des3 = new DES3Tools();
		String garbleText = plainText + "|" + des3.getGarbleString(plainText);
		return des3.base64Encode(des3.encrypt(garbleText));
	}
 
	/**
	 * 3des 通信最终解密工具
	 * 
	 * @param garbeText
	 * @return
	 */
	public static final String finalDEcode(String garbeText) {
		String plainText = null;
		DES3Tools des3 = new DES3Tools();
		byte[] tmpByte = des3.base64DEcode(garbeText);
		String tmpString = des3.decrypt(tmpByte);
		String[] tmpStrs = tmpString.split("\\|");
		if (des3.verifyString(tmpStrs)) {
			plainText = tmpStrs[0];
		} else {
 
		}
		return plainText;
	}
 
	public static void main(String[] args) {
		DES3Tools ed = new DES3Tools();
		String plainText = "2217";
		String garbleText = ed.getGarbleString(plainText);
		System.err
				.println("---------------------------------------------------------------------");
		System.out.println("生成明文混淆字符串 :" + garbleText);
		String[] strs = { plainText, garbleText };
		System.out.println("验证混淆字符串是否正确 :" + ed.verifyString(strs));
		byte[] temp = ed.encrypt(plainText + "|" + garbleText);
		String s = ed.byteArr2HexStr(temp);
		String newStr = ed.base64Encode(temp);
 
		System.out.println("加密后:" + s);
		System.out.println("解密后:" + ed.decrypt(ed.hexStr2ByteArr(s)));
		System.out.println("base64混淆后:" + newStr);
		System.out.println("base64混淆解密后:"
				+ ed.byteArr2HexStr(ed.base64DEcode(newStr)));
		System.err
				.println("=============================================================================");
		String pt = "2217";
		System.err.println("3des 加密工具使用 API 明文: " + pt);
		System.err.println("DES3Tools.finalEncode(明文参数字符串)结果:"
				+ DES3Tools.finalEncode(pt));
		String gt = "bclsmKghcNh1NLewhZFbLDl+9d2uTgHcXqA3fR4zrz8UHfg7nNzeHQ==";
		System.err.println("3des 解密工具使用 API 密文: " + gt);
		System.err.println("DES3Tools.finalDEcode(密文参数字符串)结果:"
				+ DES3Tools.finalDEcode(gt));
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.uninf.video.util.encryption;
 
import org.uninf.config.ConfigReader;
 
/**
 * 加密解密配置文件
 * 
 * @author zhangwei
 * 
 * 
 * @time 2013-1-29 上午8:50:23
 * 
 */
public class EncryptConfig {
	public static final String DES3_KEY = get("DES3_KEY");//替换你的密钥
	public static final String DES3_IV = get("DES3_IV");//替换你的IV
 
	private static String get(String name) {
		return ConfigReader.getConfigReader().get(name);
	}
}

System.nanoTime()

在Java中我们常常使用System.currentTimeMillis()来进行时间计算,它的精确度是毫秒级别的,如果我们想来的更加精确,可以使用

System.nanoTime(),这个是精确到纳米级别的方法。

我们来看一看方法注释:

/**
* Returns the current value of the most precise available system
* timer, in nanoseconds.
*
* <p>This method can only be used to measure elapsed time and is
* not related to any other notion of system or wall-clock time.
* The value returned represents nanoseconds since some fixed but
* arbitrary time (perhaps in the future, so values may be
* negative). This method provides nanosecond precision, but not
* necessarily nanosecond accuracy. No guarantees are made about
* how frequently values change. Differences in successive calls
* that span greater than approximately 292 years (2<sup>63</sup>
* nanoseconds) will not accurately compute elapsed time due to
* numerical overflow.
*
* <p> For example, to measure how long some code takes to execute:
* <pre>
* long startTime = System.nanoTime();
* // … the code being measured …
* long estimatedTime = System.nanoTime() – startTime;
* </pre>
*
* @return The current value of the system timer, in nanoseconds.
* @since 1.5
*/

此方法只能用于计时,不能用于时间推算。