Ubuntu是个很奇怪的系统。。。安装完的路径完全和官网下载安装的不一样
Tomcat一定要用7.0.5X 别的有的不好使各种报错

环境变量里一定要有JAVA_HOME,PATH里一定包含JAVA_HOME

1
2
3
4
5
6
7
cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 umw
127.0.0.1 192.168.0.121

网络对应关系需要把局域网ip对应本地ip

如果想获取客户端真实的ip应该添加remoteip这个模块

apt-get install apache2 libapache2-mod-jk

安装apache2和jk

Apache2的jk插件在/etc/apache2/mods-avalibale/jk.conf

而jk的workers.propertiy在/etc/libapache2-mod-jk/workers.propertiy

在property里指定java环境和多个tomcat

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
worker.list=loadbalancer,jkstatus
worker.tomcat1.type=ajp13
worker.tomcat1.host=localhost
worker.tomcat1.port=8009
worker.tomcat1.lbfactor=1
worker.tomcat1.socket_keepalive=1
worker.tomcat2.type=ajp13
worker.tomcat2.host=localhost
worker.tomcat2.port=9009
worker.tomcat2.lbfactor=1
worker.tomcat2.socket_keepalive=1
worker.jkstatus.type=status
worker.loadmanager.sticky_session=True
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=tomcat1,tomcat2

这个status一定要这么写 哎 累死我了各种试

在/etc/apache2/mods-avalibale/jk.conf编辑如下

加上

JkMountloadbalancer
1
2
JkMount /jkstatus jkstatus

找到 Deny from all注释掉

下面改为 Allow from all

Tomcat的配置

conf目录下

编辑web.xml

最后一行上面加上

(使多个session共享)

在server.xml里配置session和端口

1
2
3
4
5
6
7
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

这两句 第一个tomcat不用变 第二个改端口可以分别是 9090和9009,响应的端口改为9443

找到engine标签 换成一下配置

jvmRoute第二个tomcat写tomcat2

Receiver的address改为自己局域网的ip,port第二个tomcat改为4002

如果你不是在一台机器上布置两个tomcat,就不用改

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
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="192.168.0.121"
port="4001"
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>

Apache2的配置

在/etc/apache2/apache2.conf里

空白处加

ServerName localhost:80

DirectoryIndex index.html index.htm index.shtml index.cgi index.php index.php3 index.pl index.xhtml

在/etc/apache2/site-avaliable里编辑000-default.conf设置两个tomcat的虚拟主机目录

为了可以通过端口访问两个tomcat,如果不想让两个tomcat暴露的话不需要设置这个虚拟主机

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
<VirtualHost *:8080>
ServerAdmin webmaster@localhost
DocumentRoot /opt/tomcat5/webapps
ErrorLog /var/log/apache2/idealerror.log
LogLevel warn
CustomLog /var/log/apache2/idealaccess.log combined
<Directory "/opt/tomcat5/webapps/">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
<VirtualHost *:9090>
ServerAdmin webmaster@localhost
DocumentRoot /opt/tomcat6/webapps
ErrorLog /var/log/apache2/idea2error.log
LogLevel warn
CustomLog /var/log/apache2/idea2access.log combined
<Directory "/opt/tomcat6/webapps/">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

先启动tomcat再启动apache restart

直接访问局域网地址192.168.0.121就会跳转到其中一台tomcat的主页

访问http://192.168.0.121/jkstatus就可以查看apache2的状态

然后你就可以吧项目考到tomcat的webapps目录下来(两个tomcat都要考哦),重启tomcat访问项目

Apache2的相关命令

ps /etc/init.d/apache2 force-reload重载

ps /etc/init.d/apache2 restart重启

a2enmod添加插件(可查看jk是否被启用)

a2dismod卸载插件

错误日志文件 在var/log/apache2文件夹中其中有mod_jk的日志文件,

也可以查看tomcat目录下的logs文件夹内的localhost_access_log.2014-12-03.txt文件来查看tomcat与apache之间的通讯信息(比较多 看的眼花缭乱的)

过程是这样的你的网站有改动了 想要通知同时登陆的手机端,这个推送是实时的, 还有一种程序关闭 然后收到的推送 这个是第三方的推送 ios的话是服务器发送到苹果服务器 由ios_token确定推送给哪个手机,android则可以用极光推送等。。。
这里只说程序在线时实时通知的实现java哦

这里比较复杂的莫过于spring的配置了那就先上配置applicationContext.xml

mina的配置在最下面

这个 之上的 配置有velocity和memcache还有springjdbc,自动装配,json对象支持(注解@ResponseBody), 切面事务管理 , 当然这些大家能用的上的 拿走 用不上删掉(跟没说一样)

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
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="stringConverter" class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
<bean id="exceptionResolver" class="com.util.ExceptionHandler"/>
<!-- 输出对象转JSON支持 -->
<bean id="jsonConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="stringConverter"/>
<ref bean="jsonConverter" />
</list>
</property>
</bean>
<!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 -->
<!-- <context:component-scan base-package="com.controller" />
<context:component-scan base-package="com.service" />
<context:component-scan base-package="com.dao" /> -->
<context:component-scan base-package="com" />
<!-- 配置数据源 destroy-method="close"-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass">
<value>${jdbc.driverClassName}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
<!--连接池中保留的最小连接数。 -->
<property name="minPoolSize">
<value>5</value>
</property>
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize">
<value>30</value>
</property>
<!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
<property name="initialPoolSize">
<value>10</value>
</property>
<!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime">
<value>60</value>
</property>
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement">
<value>5</value>
</property>
<!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 -->
<property name="maxStatements">
<value>0</value>
</property>
<!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod">
<value>60</value>
</property>
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts">
<value>30</value>
</property>
<!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
获取连接失败后该数据源将申明已断开并永久关闭。Default: false -->
<property name="breakAfterAcquireFailure">
<value>true</value>
</property>
<!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
等方法来提升连接测试的性能。Default: false -->
<property name="testConnectionOnCheckout">
<value>false</value>
</property>
<property name="automaticTestTable">
<value>true</value>
</property>
</bean>
<!-- 配置Jdbc模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource" />
<!-- 通过AOP配置提供事务增强,让controller包下所有Bean的所有方法拥有事务 -->
<!-- <aop:config proxy-target-class="true">
<aop:pointcut id="serviceMethod"
expression=" execution(* com.controller..*(..))" />
<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice> -->
<!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<!-- VM视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="requestContextAttribute" value="rc"></property>
<property name="cache" value="true"/>
<property name="prefix" value=""/>
<property name="suffix" value=".vm"/>
<property name="contentType"><value>text/html;charset=UTF-8</value></property>
<property name="dateToolAttribute"><value>dateTool</value></property>
<property name="numberToolAttribute"><value>numberTool</value></property>
</bean>
<!-- 指定模板视图存放位置,以及编码格式 -->
<bean id="velocityConfigurer" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/WEB-INF/velo/"/>
<property name= "velocityProperties">
<props>
<prop key="input.encoding">utf-8</prop>
<prop key="output.encoding">utf-8</prop>
</props>
</property>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<!-- 访问数据库前,查询MEMCACHED缓存服务器 -->
<!-- <bean id="memcachedInterceptor" class="com.interceptor.MemcachedInterceptor"></bean>
<aop:config>
<aop:pointcut expression="execution(* select*(..))"
id="memcachedPointCut"/>
<aop:aspect id="memcachedAspect" ref="memcachedInterceptor">
<aop:aroundpointcut-ref="memcachedPointCut" method="aronud"/>
</aop:aspect>
</aop:config> -->
<!-- 官方文档地址 http://code.google.com/p/xmemcached/wiki/Spring_Integration -->
<bean
id="memcachedClientBuilder"
class="net.rubyeye.xmemcached.XMemcachedClientBuilder"
p:connectionPoolSize="20"
p:failureMode="true">
<constructor-arg>
<list>
<bean class="java.net.InetSocketAddress">
<constructor-arg>
<value>你的memcache的地址</value>
</constructor-arg>
<constructor-arg>
<value>11211</value>
</constructor-arg>
</bean>
<!-- <bean class="java.net.InetSocketAddress"> -->
<!-- <constructor-arg> -->
<!-- <value>192.168.1.2</value> -->
<!-- </constructor-arg> -->
<!-- <constructor-arg> -->
<!-- <value>10002</value> -->
<!-- </constructor-arg> -->
<!-- </bean> -->
<!-- <bean class="java.net.InetSocketAddress"> -->
<!-- <constructor-arg> -->
<!-- <value>192.168.1.3</value> -->
<!-- </constructor-arg> -->
<!-- <constructor-arg> -->
<!-- <value>10003</value> -->
<!-- </constructor-arg> -->
<!-- </bean> -->
<!-- <bean class="java.net.InetSocketAddress"> -->
<!-- <constructor-arg> -->
<!-- <value>192.168.1.4</value> -->
<!-- </constructor-arg> -->
<!-- <constructor-arg> -->
<!-- <value>4</value> -->
<!-- </constructor-arg> -->
<!-- </bean> -->
</list>
</constructor-arg>
<constructor-arg>
<list>
<value>1</value>
<!-- <value>2</value> -->
<!-- <value>3</value> -->
<!-- <value>4</value> -->
</list>
</constructor-arg>
<property name="commandFactory">
<bean class="net.rubyeye.xmemcached.command.TextCommandFactory" />
</property>
<property name="sessionLocator">
<bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator" />
</property>
<property name="transcoder">
<bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" />
</property>
</bean>
<bean
id="memcachedClient"
factory-bean="memcachedClientBuilder"
factory-method="build"
destroy-method="shutdown" />
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:defaultEncoding="utf-8"/>
<mvc:interceptors>
<!-- 拦截所有请求
<bean class="com.etoak.util.LoginCheck2"></bean>-->
<mvc:interceptor>
<mvc:mapping path="/dashboard"/>
<mvc:mapping path="/dashboard/**"/>
<mvc:mapping path="/setting"/>
<mvc:mapping path="/setting/**"/>
<bean class="com.interceptor.LoginCheck"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.interceptor.CityCheck"></bean>
</mvc:interceptor>
</mvc:interceptors>
<!-- spring && mina -->
<!-- executorFilter多线程处理 -->
<bean id="executorFilter" class="org.apache.mina.filter.executor.ExecutorFilter" />
<bean id="mdcInjectionFilter" class="org.apache.mina.filter.logging.MdcInjectionFilter">
<constructor-arg value="remoteAddress" />
</bean>
<bean id="codecFilter" class="org.apache.mina.filter.codec.ProtocolCodecFilter">
<constructor-arg>
<!-- <bean class="org.apache.mina.filter.codec.textline.TextLineCodecFactory" />-->
<!-- 处理对象流时候用ObjectSerializationCodecFactory -->
<!-- <bean class="org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory" /> -->
<bean class="com.umaiw.socket.ServerCodeFactory" />
</constructor-arg>
</bean>
<bean id="loggingFilter" class="org.apache.mina.filter.logging.LoggingFilter" />
<bean id="filterChainBuilder" class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder">
<property name="filters">
<map>
<entry key="executor" value-ref="executorFilter" />
<entry key="mdcInjectionFilter" value-ref="mdcInjectionFilter" />
<entry key="codecFilter" value-ref="codecFilter" />
<entry key="loggingFilter" value-ref="loggingFilter" />
</map>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.net.SocketAddress">
<bean class="org.apache.mina.integration.beans.InetSocketAddressEditor" />
</entry>
</map>
</property>
</bean>
<!-- session config -->
<bean id="sessionConfig" factory-bean="ioAcceptor"
factory-method="getSessionConfig" >
<property name="readerIdleTime" value="50"/>
</bean>
<bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor" init-method="bind" destroy-method="unbind">
<property name="defaultLocalAddress" value=":10000" />
<property name="handler" ref="dataHandler" />
<property name="filterChainBuilder" ref="filterChainBuilder" />
<property name="reuseAddress" value="true" />
</bean>
<bean id="dataHandler" class="com.umaiw.socket.DataHandler">
</bean>
<!--这里是udp的部分 如果想用请下载udp部分的代码 会在最下面有下载-->
<!-
<bean id="udpAcceptor" class="org.apache.mina.transport.socket.nio.NioDatagramAcceptor" init-method="bind" destroy-method="unbind">
<property name="defaultLocalAddress" value=":10001" />
<property name="handler" ref="UdpHandler" />
<property name="filterChainBuilder" ref="filterChainBuilder" />
</bean>
<bean id="UdpHandler" class="com.umaiw.socket.UdpHandler">
</bean>
-->
</beans>

如果需要数据库连接的话 再src下面再写个jdbc.properties具体怎么写大家都会把 好吧给个例子

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://你的数据库地址哦:3306/umaiwtest?relaxAutoCommit=true&zeroDateTimeBehavior=convertToNull
jdbc.username=test
jdbc.password=test

然后是DataHandler 处理各种事件的地方

其中的messageRecive方法里调用的

1
2
3
4
String result=constants.getClassName(Long.parseLong(command));
Command cmd = (Command)constants.newCommand(result);
cmd.action(session, other);

则是吧处理的业务逻辑写成了实现command的接口都有一个action方法

然后动态加载command这个对应名字类的方法

这里是按 : 来分隔参数的

package com.umaiw.socket;
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
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.mina.core.future.CloseFuture;
import org.apache.mina.core.future.IoFuture;
import org.apache.mina.core.future.IoFutureListener;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.model.UserSession;
import com.model.umaiw_app_system;
import com.service.GetInitKeyService;
import com.service.implement.GetInitKeyServiceImpl;
import com.umaiw.command.Command;
import com.umaiw.command.Constants;
import com.umaiw.command.SocketModel;
import com.util.DesUtil;
@Component("DataHandler")
public class DataHandler extends IoHandlerAdapter implements Runnable{
@Autowired
private Constants constants;
private final static Logger log = LoggerFactory.getLogger(DataHandler.class);
private final Set<IoSession> sessions = Collections.synchronizedSet(new HashSet<IoSession>());
//private UserSession UserSession;
@Autowired
private static Map<String,IoSession> users = Collections.synchronizedMap(new HashMap<String,IoSession>());
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
log.error(" 有异常发生时被触发exceptionCaught。",cause);
session.close(true);
}
@Override
public void sessionCreated(IoSession session) throws Exception {
log.info("当创建一个新连接时被触发,即当开始一个新的Session时被触发。");
log.info("创建一个新连接:{}", session.getRemoteAddress());
/*//50秒无读写操作就触发idele
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 50);*/
sessions.add(session);
log.info("并发的个数:\t"+sessions.size());
session.setAttribute("command",1);
messageSentSingle(session, "创建了一个socket连接哦");
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
log.info("服务器接收到数据: {}", message);
String[] mes=message.toString().split(":");
String version=mes[0];//协议版本号
String ID=mes[1];//包ID(10进制)
String mark=mes[2];//唯一标识
String mobile=mes[3];//手机号码
String command=mes[4];//命令ID(10进制)
String[] other=new String[mes.length*2];
if(mes.length>5){
for(int i=5;i<mes.length;i++){
int x=0;
other[x]=mes[i];
x++;
}
}
if(mobile==null){
mobile="1";
}
session.setAttribute("mobile",mobile);
String result=constants.getClassName(Long.parseLong(command));
Command cmd = (Command)constants.newCommand(message);
cmd.action(session, message);
Object oldpacket_id=session.getAttribute("packet_id");
if(oldpacket_id!=null){
session.setAttribute("oldpacket_id",oldpacket_id);
}
String packet_id=new Date().getTime()+"";
session.setAttribute("packet_id",packet_id);
session.setAttribute("command",Integer.parseInt(command));
// messageSentSingle(session, "业务处理完了");
}
public static void messageSentAll( Object message) throws Exception {
log.info("发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。=" + message);
// 向所有客户端发送的数据
SocketModel socm=new SocketModel(new Date().getTime()+"", "", 5, message);
String send=socm.toString();
Collection<IoSession> sessions = users.values();
for (IoSession sess : sessions) {
sess.write(send);
}
}
public static void messageSentSingle(IoSession session, Object message) throws Exception {
log.info("发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。=" + message);
// 向所有客户端发送的数据
Integer command=(Integer) session.getAttribute("command");
SocketModel socm=new SocketModel(new Date().getTime()+"", "", command, message);
String send=socm.toString();
session.write(send);
}
public static void messageSentPart( Object message,String city_id) throws Exception {
log.info("发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。=" + message);
Object[] key=users.keySet().toArray();
for (int i = 0; i < key.length; i++) {
if(key[i].toString().contains(city_id)){
IoSession iosession=users.get(key[i]);
SocketModel socm=new SocketModel(new Date().getTime()+"", "", 5, message);
String send=socm.toString();
iosession.write(send);
}
}
// 向所有客户端发送的数据
}
public static Map<String, IoSession> getUsers() {
return users;
}
@Override
public void sessionClosed(IoSession session) throws Exception {
log.info("关闭当前session:{}#{}", session.getId(), session.getRemoteAddress());
CloseFuture closeFuture = session.close(true);
closeFuture.addListener(new IoFutureListener<IoFuture>() {
public void operationComplete(IoFuture future) {
if (future instanceof CloseFuture) {
((CloseFuture) future).setClosed();
log.info("sessionClosed CloseFuture setClosed-->{},", future.getSession().getId());
}
}
});
UserSession userSession= (UserSession) session.getAttribute("UserSession");
String mobile=(String) session.getAttribute("mobile");
if(null!=mobile&&userSession!=null){
users.remove(mobile+"+"+userSession.getCity_id());
}
sessions.remove(session);
log.info("关闭的连接的剩余的个数:\t"+sessions.size());
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
// session.close();
log.info("IDLE " + session.getIdleCount(status)+"次;"+"user个数"+users.size()+"sessions个数"+sessions.size());
if(session.getIdleCount(status) > 5){
log.info("连接空闲= " + session.getIdleCount(status)+",触发session关闭");
session.close(true);
}
}
@Override
public void sessionOpened(IoSession session) throws Exception {
log.info("进入当打开一个连接时被触发sessionOpened!");
log.info("打开一个session:{}#{}", session.getId(), session.getBothIdleCount());
try {
super.sessionOpened(session);
} catch (Exception e) {
log.error("",e);
}
}
@Override
public void messageSent(IoSession session, Object message) throws Exception {
log.info("发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。=" + message);
try {
super.messageSent(session, message);
} catch (Exception e) {
log.error("",e);
}
}
}
}

然后是处理业务逻辑的command接口 和实现它的类(这里就举1个例子,多写业务处理 就再多些点实现类就行)

command.java

package com.umaiw.command;
1
2
3
4
5
6
import org.apache.mina.core.session.IoSession;
public interface Command {
public void action(IoSession session,String[] other) ;
}

UMMSG_TCP_SENDINFORMATIONTOSERVER.java(业务逻辑处理)

package com.umaiw.command;
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
import org.apache.mina.core.session.IoSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import com.model.UserSession;
import com.service.LoginService;
import com.service.implement.LoginServiceImpl;
import com.umaiw.socket.DataHandler;
@Component("UMMSG_TCP_SENDINFORMATIONTOSERVER")
public class UMMSG_TCP_SENDINFORMATIONTOSERVER implements Command {
@Autowired
private LoginService loginService ;
@Override
public void action(IoSession session, String[] param) {
String mobile=(String) session.getAttribute("mobile");
UserSession user= loginService.getUserSession(mobile);
session.setAttribute("UserSession",user);
DataHandler.getUsers().put(mobile+"+"+user.getCity_id(), session);
//DataHandler.messageSentSingle(session, s);
}
}

接下来是根据传过来的command来找是哪个处理类的类

Constants.java

这里注册了三个类(上面给了一个类UMMSG_TCP_SENDINFORMATIONTOSERVER的例子,别的照着写就行啦)

package com.umaiw.command;
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
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("Constants")
public class Constants {
@Autowired
private UMMSG_TCP_CHECKCLIENT uMMSG_TCP_CHECKCLIENT;
@Autowired
private UMMSG_TCP_MAKESURECEIVE uMMSG_TCP_MAKESURECEIVE;
@Autowired
private UMMSG_TCP_SENDINFORMATIONTOSERVER uMMSG_TCP_SENDINFORMATIONTOSERVER;
@Autowired
private Map<String, Object> registry = new HashMap<String, Object>();
@Autowired
private void res() {
// 2、客户端发送口令供服务器端验证
registry.put(UMMSG_TCP_CHECKCLIENT_name, uMMSG_TCP_CHECKCLIENT);
// 3、客户端发送身份信息给服务器
registry.put(UMMSG_TCP_SENDINFORMATIONTOSERVER_name,
uMMSG_TCP_SENDINFORMATIONTOSERVER);
// 4、客户端发送回执给服务器
registry.put(UMMSG_TCP_MAKESURECEIVE_name, uMMSG_TCP_MAKESURECEIVE);
}
// 方法对应值与类名
// 2、客户端发送口令供服务器端验证
public static final int UMMSG_TCP_CHECKCLIENT_code = 0x00000002;
public static final String UMMSG_TCP_CHECKCLIENT_name = "UMMSG_TCP_CHECKCLIENT";
// 3、客户端发送身份信息给服务器
public static final int UMMSG_TCP_SENDINFORMATIONTOSERVER_code = 0x00000003;
public static final String UMMSG_TCP_SENDINFORMATIONTOSERVER_name = "UMMSG_TCP_SENDINFORMATIONTOSERVER";
// 4、客户端发送回执给服务器
public static final int UMMSG_TCP_MAKESURECEIVE_code = 0x00000004;
public static final String UMMSG_TCP_MAKESURECEIVE_name = "UMMSG_TCP_MAKESURECEIVE";
// 注册到registry集合里好使用
public String getClassName(long code) {
if (code == UMMSG_TCP_SENDINFORMATIONTOSERVER_code) {
return UMMSG_TCP_SENDINFORMATIONTOSERVER_name;
} else if (code == UMMSG_TCP_SENDINFORMATIONTOSERVER_code) {
return UMMSG_TCP_SENDINFORMATIONTOSERVER_name;
} else if (code == UMMSG_TCP_MAKESURECEIVE_code) {
return UMMSG_TCP_MAKESURECEIVE_name;
} else if (code == UMMSG_TCP_CHECKCLIENT_code) {
return UMMSG_TCP_CHECKCLIENT_name;
}
return null;
}
public Object newCommand(String name) {
return registry.get(name);
}
// 获得无符号值
public static int getUnsignedValue(byte bt) {
int i = bt;
if (bt < 0) {
i = 257 + i;
}
return i;
}
// 获得无符号值
public static long getLongValue(byte[] bt) {
long l = 0;
for (int i = 0; i < bt.length; i++) {
l = (l << 8) | (bt[i] & 0xff);
}
return l;
}
public String getClassName(byte[] bt) {
return getClassName(getLongValue(bt));
}
/**
* @since Integer转换byte[]
* @param len
* @return
*/
public static byte[] getByteByInt(Integer len, int buffer) {
byte[] b = new byte[buffer];
for (int i = b.length - 1; i > -1; i--) {
b[i] = new Integer(len & 0xff).byteValue();// 将最高位保存在最低位
len = len >> 8; // 向右移8位
}
return b;
}
public static byte[] getByteByStr(String len, int buffer) {
byte[] bt = new byte[buffer];
System.arraycopy(len.getBytes(), 0, bt, 0, len.getBytes().length);
return bt;
}
public static void main(String[] args) {
// getByteByStr("123", 6);
// byte[] bt = new byte[4];
// bt[0] = (byte) 0x00;
// bt[1] = (byte) 0x00;
// bt[2] = (byte) 0x00;
// bt[3] = (byte) 0x01;
// System.out.println(Constants.getLongValue(bt));
// System.out.println(Constants.getLongValue(Constants
// .getByteByInt(110, 4)));
// getByteByInt(0x10000001, 4);
System.err.println(Integer.MAX_VALUE);
}
}

接下来是socketmodel 就是用来整理发送消息的格式的

SocketModel.java

package com.umaiw.command;
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
public class SocketModel {
private String version="UM";
private String id;
private String mark="";
private String mobile;
private Object other;
private Integer command;
public SocketModel( String id, String mobile,
Integer command,Object other) {
this.id = id;
this.mobile = mobile;
this.other = other;
this.command = command;
}
public String toString() {
return version+":"+id+":"+mark+":"+mobile+":"+command+":"+other+(char)7;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMark() {
return mark;
}
public void setMark(String mark) {
this.mark = mark;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public Object getOther() {
return other;
}
public void setOther(Object other) {
this.other = other;
}
public Integer getCommand() {
return command;
}
public void setCommand(Integer command) {
this.command = command;
}
}

最后是mina必备的codefactory和decode,encode

ServerCodeFactory.java

package com.umaiw.socket;
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
import java.nio.charset.Charset;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineDecoder;
import org.apache.mina.filter.codec.textline.TextLineEncoder;
public class ServerCodeFactory implements ProtocolCodecFactory {
private final ProtocolEncoder encoder;
private final ProtocolDecoder decoder;
/*final static char endchar = 0x1a;*/
final static char endchar = 0x0d;
public ServerCodeFactory() {
this(Charset.forName("utf-8"));
}
public ServerCodeFactory(Charset charset) {
encoder = new CharsetEncoder();
decoder = new CharsetDecoder();
}
@Override
public ProtocolDecoder getDecoder(IoSession session) throws Exception {
// TODO Auto-generated method stub
return decoder;
}
@Override
public ProtocolEncoder getEncoder(IoSession session) throws Exception {
// TODO Auto-generated method stub
return encoder;
}
public ProtocolEncoder getEncoder() {
return encoder;
}
public ProtocolDecoder getDecoder() {
return decoder;
}
}

CharsetDecoder.java (这里用(char)7当结束标志)

package com.umaiw.socket;
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
import java.nio.charset.Charset;
import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
/**
* <b>function:</b> 字符解码
* @author hoojo
* @createDate 2012-6-26 上午11:14:18
* @file CharsetDecoder.java
* @package com.hoo.mina.code
* @project ApacheMiNa
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class CharsetDecoder implements ProtocolDecoder {
private final static Logger log = Logger.getLogger(CharsetDecoder.class);
private final static Charset charset = Charset.forName("UTF-8");
// 可变的IoBuffer数据缓冲区
private IoBuffer buff = IoBuffer.allocate(100).setAutoExpand(true);
@Override
public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
log.info("#########decode#########");
// 如果有消息
while (in.hasRemaining()) {
// 判断消息是否是结束符,不同平台的结束符也不一样;
// windows换行符(\r\n)就认为是一个完整消息的结束符了; UNIX 是\n;MAC 是\r
byte b = in.get();
if (b == (char)7) {
buff.flip();
byte[] bytes = new byte[buff.limit()];
buff.get(bytes);
String message = new String(bytes, charset);
buff = IoBuffer.allocate(100).setAutoExpand(true);
// 如果结束了,就写入转码后的数据
out.write(message);
log.info("message: " + message);
} else {
buff.put(b);
}
}
}
@Override
public void dispose(IoSession session) throws Exception {
log.info("#########dispose#########");
log.info(session.getCurrentWriteMessage());
}
@Override
public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception {
log.info("#########完成解码#########");
}
}

CharsetEncoder.java

package com.umaiw.socket;
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
import java.nio.charset.Charset;
import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.textline.LineDelimiter;
/**
* <b>function:</b> 字符编码
* @author hoojo
* @createDate 2012-6-26 上午11:32:05
* @file CharsetEncoder.java
* @package com.hoo.mina.code
* @project ApacheMiNa
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class CharsetEncoder implements ProtocolEncoder {
private final static Logger log = Logger.getLogger(CharsetEncoder.class);
private final static Charset charset = Charset.forName("UTF-8");
@Override
public void dispose(IoSession session) throws Exception {
log.info("#############dispose############");
}
@Override
public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
log.info("#############字符编码############");
IoBuffer buff = IoBuffer.allocate(100).setAutoExpand(true);
buff.putString(message.toString(), charset.newEncoder());
// put 当前系统默认换行符
// buff.putString(LineDelimiter.DEFAULT.getValue(), charset.newEncoder());
// 为下一次读取数据做准备
buff.flip();
out.write(buff);
}
}

http://yun.baidu.com/share/link?shareid=927201255&uk=958682606

微信开发者中心 配置url和token的时候 总出现配置失败,需要注意的是80端口和点击提交的时候微信会对你的url发送一个验证get请求,
需要验证来的signature正确返回echostr。还有后来的前台js获取token和ticket等签名的请求 spring mvc处理的

controller

@RequestMapping("/weixin")
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
@ResponseBody
public String weixin(String signature,String timestamp
,String nonce,String echostr) throws NoSuchAlgorithmException {
String token="umaiw";
String tmpStr= getSHA1(token, timestamp, nonce);
System.out.println("+++++++++++++++++++++tmpStr "+tmpStr);
System.out.println("---------------------signature "+signature);
if(tmpStr.equals(signature)){
return echostr;
}else{
return null;
}
/**
* 用SHA1算法生成安全签名
* @param token 票据
* @param timestamp 时间戳
* @param nonce 随机字符串
* @param encrypt 密文
* @return 安全签名
* @throws NoSuchAlgorithmException
* @throws AesException
*/
public String getSHA1(String token, String timestamp, String nonce) throws NoSuchAlgorithmException {
String[] array = new String[] { token, timestamp, nonce };
StringBuffer sb = new StringBuffer();
// 字符串排序
Arrays.sort(array);
for (int i = 0; i < 3; i++) {
sb.append(array[i]);
}
String str = sb.toString();
// SHA1签名生成
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(str.getBytes());
byte[] digest = md.digest();
StringBuffer hexstr = new StringBuffer();
String shaHex = "";
for (int i = 0; i < digest.length; i++) {
shaHex = Integer.toHexString(digest[i] & 0xFF);
if (shaHex.length() < 2) {
hexstr.append(0);
}
hexstr.append(shaHex);
}
return hexstr.toString();
}

Sign.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
package com.util;
import java.util.UUID;
import java.util.Map;
import java.util.HashMap;
import java.util.Formatter;
import java.util.concurrent.TimeoutException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import net.rubyeye.xmemcached.exception.MemcachedException;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("Sign")
public class Sign {
@Autowired
private WeiXinRequest weiXinRequest;
@Test
public Map<String, String> test(HttpServletRequest requesturl) throws IOException, TimeoutException, InterruptedException, MemcachedException {
String ticket= weiXinRequest.getWeiXinTicket();
// 注意 URL 一定要动态获取,不能 hardcode
String url = requesturl.getRequestURL().toString();
Map<String, String> ret = sign(ticket, url);
for (Map.Entry entry : ret.entrySet()) {
System.out.println(entry.getKey() + ", " + entry.getValue());
}
ret.put("appId",weiXinRequest.appId );
return ret;
};
public static Map<String, String> sign(String jsapi_ticket, String url) {
Map<String, String> ret = new HashMap<String, String>();
String nonce_str = create_nonce_str();
String timestamp = create_timestamp();
String string1;
String signature = "";
//注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + jsapi_ticket +
"&noncestr=" + nonce_str +
"&timestamp=" + timestamp +
"&url=" + url;
System.out.println(string1);
try
{
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
ret.put("url", url);
ret.put("jsapi_ticket", jsapi_ticket);
ret.put("nonceStr", nonce_str);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
return ret;
}
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
private static String create_nonce_str() {
return UUID.randomUUID().toString();
}
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}

WeiXinRequest.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
package com.util;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import javax.servlet.http.HttpServletRequest;
import javax.xml.crypto.Data;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.exception.MemcachedException;
import org.activiti.engine.impl.util.json.JSONObject;
import org.activiti.engine.impl.util.json.JSONTokener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.model.CitySession;
@Component("WeiXinRequest")
public class WeiXinRequest {
@Autowired
private MemcachedClient memcachedClient;
String appId = "你扫描后登陆进去的appid 不同人不一样哦";
private String appSecret="同上";
public String getWeiXinTicket() throws IOException, TimeoutException, InterruptedException, MemcachedException {
String access_token="";
String ticket="";
Object act=memcachedClient.get("access_token");
Object apiticket=memcachedClient.get("ticket");
Object expires_in ;
if(null==act){
URL url = new URL(
"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
+ appId + "&secret=" + appSecret);
JSONObject json = getConnection(url);
access_token = (String) json.getString("access_token");
expires_in= json.get("expires_in");
if (access_token == null) {
return null;
}
memcachedClient.set("access_token", 2*60*60, access_token);
}else{
access_token=(String) act;
}
System.out.println("access_token is =====" + access_token);
if(null==apiticket){
URL url1=new URL("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+access_token+"&type=jsapi");
JSONObject json1 = getConnection(url1);
ticket=(String) json1.get("ticket");
}else{
ticket=(String) apiticket;
}
return ticket;
// 断开连接
}
public JSONObject getConnection(URL url) throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("GET");
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(true);
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
connection.connect();
JSONObject jsono = new JSONObject(new JSONTokener(
new InputStreamReader(connection.getInputStream())));
connection.disconnect();
return jsono;
}
}

js发送请求的controller

1
2
3
4
5
6
7
8
9
10
11
/*
* json数据格式测试
*/
@RequestMapping(value = "/house/index1")
public ModelAndView index(HttpServletRequest request,
HttpServletResponse response, ModelMap modelMap,
HttpSession session) throws IOException, TimeoutException, InterruptedException, MemcachedException {
Map<String, String> map=sign.test(request);
modelMap.addAllAttributes(map);
return new ModelAndView("/views/index/weixintest",modelMap);
}

截取返回来的json串获取城市 比如”青岛市” 获得”青岛”

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
URL url = new
URL("http://ip.taobao.com/service/getIpInfo.php?ip="+"27.223.68.94");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection(); connection.setDoOutput(true);
connection.setDoInput(true); connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(true);
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
connection.connect();
JSONObject jsono = new JSONObject(new JSONTokener(
new InputStreamReader(connection.getInputStream())));
String city = "";
String rep = jsono.toString();
String[] s = rep.split(",");
for (int i = 0; i < s.length; i++) {
if (s[i].contains("市")) {
if (s[i].length() > 8) {
city = s[i].substring(8, s[i].length() - 2);
break;
} else {
city = "";
}
}
}
System.out.println(city);

学习笔记 学习笔记 学习笔记

一个类总结下~~~~

不对的地方请大家不吝赐教^^

package com.util;
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
import java.util.concurrent.atomic.AtomicLong;
import org.apache.http.annotation.GuardedBy;
import org.apache.http.annotation.Immutable;
import org.apache.http.annotation.ThreadSafe;
@ThreadSafe
//@Immutable //程序内的变量一旦形成就不可改变 final( 如果变量是集合 那么集合内的引用将可变并不是final)
public class threadTest {
//线程同步策略@GuardedBy("this") 无状态的只能在这个类用 和AtomicLong显式锁(保证计数的原子性)
@GuardedBy("this")private final AtomicLong value=new AtomicLong(0);
//线程同步的方法synchronized(自动加互斥锁 只有一个线程可以访问此方法 )
//内置锁是可以重入的 jvm会给锁创建一个计数值和一个持有者,同一个持有者访问则计数值+1,执行完则—1直到为0 次锁释放(子类调用父类的示例)
public synchronized Long getvalue(){
return value.incrementAndGet();
}
//bad example线程readerthread可能永远循环下去、也可能输出42 或者输出0
//这就是没有同步的结果
private static boolean ready;
private static int number;
//解决方法 在变量上加private volatile static boolean ready; 这样将使ready对别的线程可见
//之所以这里不能出现看不见的状态 因为eclipse吧代码当成自己的任务去执行 都在一个进程下
public static class ReaderThread extends Thread{ //extends ThreadLocal线程封闭技术,不与线程共享数据,也就是不需要同步
public void run(){
while (!ready) {
//Thread.yield();//让线程进入执行状态,可加可不加
System.out.println(number);
}
}
}
public static void main(String[] args) throws InterruptedException {
new ReaderThread().start();
//Thread.sleep(1);
number=42;
// Thread.sleep(1);
ready=true;
}
}

因为数据库导出的是excel表格 需要根据里面的电话号来群发短信,需要jxl.jar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
String excelFileName = "d:\\dy.xls";
List<String[]> list = readExcel(new File(excelFileName), 1);
int lsize=0;
for (int i = 0; i < list.size(); i++) {
lsize=lsize+list.get(i).length;
}
String[] str1 = new String[lsize];
for (int i = 0; i < list.size(); i++) {
String[] str = (String[]) list.get(i);
for (int j = 0; j < str.length; j++) {
str1[i + j] = str[j];
}
}
for (int x = 0; x < str1.length; x++) {
System.out.println(str1[x]);
}

上面是调用方法或得到的str1就是字符串数组可以用来发短信调用

下面是读取excel的方法

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
/**
*
* @param excelFile
* 读取文件对象
* @param rowNum
* 从第几行开始读,如果有一行表头则从第二行开始读
* @return
* @throws BiffException
* @throws IOException
*/
public static List<String[]> readExcel(File excelFile, int rowNum)
throws BiffException, IOException {
// 创建一个list 用来存储读取的内容
List<String[]> list = new ArrayList<String[]>();
Workbook rwb = null;
Cell cell = null;
// 创建输入流
InputStream stream = new FileInputStream(excelFile);
// 获取Excel文件对象
rwb = Workbook.getWorkbook(stream);
// 获取文件的指定工作表 默认的第一个
Sheet sheet = rwb.getSheet(0);
// 行数(表头的目录不需要,从1开始)
for (int i = rowNum - 1; i < sheet.getRows(); i++) {
// 创建一个数组 用来存储每一列的值
String[] str = new String[sheet.getColumns()];
// 列数
for (int j = 0; j < sheet.getColumns(); j++) {
// 获取第i行,第j列的值
cell = sheet.getCell(j, i);
str[j] = cell.getContents();
}
// 把刚获取的列存入list
list.add(str);
}
// 返回值集合
return list;
}

最后这个是jxl.jar
http://pan.baidu.com/s/1sj8tRR3

这样就不用每次去new一个客户端了~~

配置cxf的系统环境变量

客户端代码生成用wsdl2java XXX?wsdl(地址)

然后找到那个interface的接口方法

在配置文件里加入

1
2
3
<!--cxf -->
<jaxws:client id="webServiceClient" serviceClass="com.util.entinfo.WebServiceHttpPost" address="http://sdk.entinfo.cn:8061/webservice.asmx">
</jaxws:client>

在程序里就可以直接用这个方法了

1
2
@Autowired
private WebServiceHttpPost webServiceHttpPost;

如何在mysql里实现 oracle里的两表联查 cat.id=dog.id(+)这种 为空补全的方法
left 或者right outer join
想在哪个表补全 就放在 left或者 right

in查询 可以用left semi join 来代替(注意join表不能在select字段中出现)

jdbc获取最后插入生成的id

1
2
3
4
5
6
7
8
ps = conn.prepareStatement("insert into test(name) value(?)",Statement.RETURN_GENERATED_KEYS);
ps.setString(1, "test");
ps.execute();
rs = ps.getGeneratedKeys();
int id=0;//保存生成的ID
if (rs != null&&rs.next()) {
id=rs.getInt(1)
}

补充下 因为max(XXXX)函数在mysql里 不知为什么
当max(整形time)时候 居然返回的不是最大的那个整形时间~。~ 哭死了 造成逻辑一直不对

所以 我用 order by time desc 在加上limit 0,1 这样组合获取到了最大值
哎 那位大侠能告诉我 为什么mysql里max函数不好使。。。。。。

还有mysql查看慢查询语句

mysql的查询语句数
show global status like ‘com_select’;
mysql的查询连接数
show global status like ‘connections’;

连接到mysql的ip
netstat -an
进程号
netstat -anb

显示慢查询的次数(默认10秒)
show status like ‘slow_queries’;
把慢查询的sql记录到日志中
需要在启动的时候指定慢查询
bin\mysqld.exe –safe-mode –slow-query-log ( 高版本5.5 在my.ini指定)
bin\mysqld.exe - log-slow-queries=d:/abc.log (低版本5.0 在my.ini指定)
先关闭再重新启动(先停止服务)
默认吧日志文件放在my.ini里有个datadir路径下
重新设置慢查询为1秒

设置慢查询为1秒
show variables like ‘long_query_time’;
set long_query_time=1;

为了存储过程能正常执行,需要把命令结束符号修改为不为;
delimiter $$
修改为$$

处理多条数据的时候
set autocommit==0;
…….
commit;

存储过程里的for循环
repeat
set i=i+1;
…..
until i=max_num
end repeat;

网上有一个没给调用方法的 这里补充下,还有个java自带的图片压缩方法
BiCubicInterpolationScale.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
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
package com.util;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
public class BiCubicInterpolationScale {
private static double a00, a01, a02, a03;
private static double a10, a11, a12, a13;
private static double a20, a21, a22, a23;
private static double a30, a31, a32, a33;
private static int srcWidth;
private static int srcHeight;
/**
* 双立方插值
* @param inPixelsData 像素矩阵数组
* @param srcW 原图像的宽
* @param srcH 原图像的高
* @param destW 目标图像的宽
* @param destH 目标图像的高
* @return 处理后的推三矩阵数组
*/
public static int[] imgScale(int[] inPixelsData, int srcW, int srcH, int destW, int destH) {
double[][][] input3DData = processOneToThreeDeminsion(inPixelsData, srcH, srcW);
int[][][] outputThreeDeminsionData = new int[destH][destW][4];
double[][] tempPixels = new double[4][4];
float rowRatio = ((float)srcH)/((float)destH);
float colRatio = ((float)srcW)/((float)destW);
srcWidth = srcW;
srcHeight = srcH;
for(int row=0; row<destH; row++) {
// convert to three dimension data
double srcRow = ((float)row)*rowRatio;
double j = Math.floor(srcRow);
double t = srcRow - j;
for(int col=0; col<destW; col++) {
double srcCol = ((float)col)*colRatio;
double k = Math.floor(srcCol);
double u = srcCol - k;
for(int i=0; i<4; i++) {
tempPixels[0][0] = getRGBValue(input3DData,j-1, k-1,i);
tempPixels[0][1] = getRGBValue(input3DData,j-1, k, i);
tempPixels[0][2] = getRGBValue(input3DData, j-1,k+1, i);
tempPixels[0][3] = getRGBValue(input3DData, j-1, k+2,i);
tempPixels[1][0] = getRGBValue(input3DData, j, k-1, i);
tempPixels[1][1] = getRGBValue(input3DData, j, k, i);
tempPixels[1][2] = getRGBValue(input3DData, j, k+1, i);
tempPixels[1][3] = getRGBValue(input3DData, j, k+2, i);
tempPixels[2][0] = getRGBValue(input3DData, j+1,k-1,i);
tempPixels[2][1] = getRGBValue(input3DData, j+1, k, i);
tempPixels[2][2] = getRGBValue(input3DData, j+1, k+1, i);
tempPixels[2][3] = getRGBValue(input3DData, j+1, k+2, i);
tempPixels[3][0] = getRGBValue(input3DData, j+2, k-1, i);
tempPixels[3][1] = getRGBValue(input3DData, j+2, k, i);
tempPixels[3][2] = getRGBValue(input3DData, j+2, k+1, i);
tempPixels[3][3] = getRGBValue(input3DData, j+2, k+2, i);
// update coefficients
updateCoefficients(tempPixels);
outputThreeDeminsionData[row][col][i] = getPixelValue(getValue(t, u));
}
}
}
return convertToOneDim(outputThreeDeminsionData, destW, destH);
}
private static double getRGBValue(double[][][] input3DData, double row, double col, int index) {
if(col >= srcWidth) {
col = srcWidth - 1;
}
if(col < 0) {
col = 0;
}
if(row >= srcHeight) {
row = srcHeight - 1;
}
if(row < 0) {
row = 0;
}
return input3DData[(int)row][(int)col][index];
}
private static int getPixelValue(double pixelValue) {
return pixelValue < 0 ? 0: pixelValue >255.0d ?255:(int)pixelValue;
}
private static void updateCoefficients (double[][] p) {
a00 = p[1][1];
a01 = -.5*p[1][0] + .5*p[1][2];
a02 = p[1][0] - 2.5*p[1][1] + 2*p[1][2] - .5*p[1][3];
a03 = -.5*p[1][0] + 1.5*p[1][1] - 1.5*p[1][2] + .5*p[1][3];
a10 = -.5*p[0][1] + .5*p[2][1];
a11 = .25*p[0][0] - .25*p[0][2] - .25*p[2][0] + .25*p[2][2];
a12 = -.5*p[0][0] + 1.25*p[0][1] - p[0][2] + .25*p[0][3] + .5*p[2][0] - 1.25*p[2][1] + p[2][2] - .25*p[2][3];
a13 = .25*p[0][0] - .75*p[0][1] + .75*p[0][2] - .25*p[0][3] - .25*p[2][0] + .75*p[2][1] - .75*p[2][2] + .25*p[2][3];
a20 = p[0][1] - 2.5*p[1][1] + 2*p[2][1] - .5*p[3][1];
a21 = -.5*p[0][0] + .5*p[0][2] + 1.25*p[1][0] - 1.25*p[1][2] - p[2][0] + p[2][2] + .25*p[3][0] - .25*p[3][2];
a22 = p[0][0] - 2.5*p[0][1] + 2*p[0][2] - .5*p[0][3] - 2.5*p[1][0] + 6.25*p[1][1] - 5*p[1][2] + 1.25*p[1][3] + 2*p[2][0] - 5*p[2][1] + 4*p[2][2] - p[2][3] - .5*p[3][0] + 1.25*p[3][1] - p[3][2] + .25*p[3][3];
a23 = -.5*p[0][0] + 1.5*p[0][1] - 1.5*p[0][2] + .5*p[0][3] + 1.25*p[1][0] - 3.75*p[1][1] + 3.75*p[1][2] - 1.25*p[1][3] - p[2][0] + 3*p[2][1] - 3*p[2][2] + p[2][3] + .25*p[3][0] - .75*p[3][1] + .75*p[3][2] - .25*p[3][3];
a30 = -.5*p[0][1] + 1.5*p[1][1] - 1.5*p[2][1] + .5*p[3][1];
a31 = .25*p[0][0] - .25*p[0][2] - .75*p[1][0] + .75*p[1][2] + .75*p[2][0] - .75*p[2][2] - .25*p[3][0] + .25*p[3][2];
a32 = -.5*p[0][0] + 1.25*p[0][1] - p[0][2] + .25*p[0][3] + 1.5*p[1][0] - 3.75*p[1][1] + 3*p[1][2] - .75*p[1][3] - 1.5*p[2][0] + 3.75*p[2][1] - 3*p[2][2] + .75*p[2][3] + .5*p[3][0] - 1.25*p[3][1] + p[3][2] - .25*p[3][3];
a33 = .25*p[0][0] - .75*p[0][1] + .75*p[0][2] - .25*p[0][3] - .75*p[1][0] + 2.25*p[1][1] - 2.25*p[1][2] + .75*p[1][3] + .75*p[2][0] - 2.25*p[2][1] + 2.25*p[2][2] - .75*p[2][3] - .25*p[3][0] + .75*p[3][1] - .75*p[3][2] + .25*p[3][3];
}
private static double getValue (double x, double y) {
double x2 = x * x;
double x3 = x2 * x;
double y2 = y * y;
double y3 = y2 * y;
return (a00 + a01 * y + a02 * y2 + a03 * y3) +
(a10 + a11 * y + a12 * y2 + a13 * y3) * x +
(a20 + a21 * y + a22 * y2 + a23 * y3) * x2 +
(a30 + a31 * y + a32 * y2 + a33 * y3) * x3;
}
/* <p> The purpose of this method is to convert the data in the 3D array of ints back into </p>
* <p> the 1d array of type int. </p>
*
*/
private static int[] convertToOneDim(int[][][] data, int imgCols, int imgRows) {
// Create the 1D array of type int to be populated with pixel data
int[] oneDPix = new int[imgCols * imgRows * 4];
// Move the data into the 1D array. Note the
// use of the bitwise OR operator and the
// bitwise left-shift operators to put the
// four 8-bit bytes into each int.
for (int row = 0, cnt = 0; row < imgRows; row++) {
for (int col = 0; col < imgCols; col++) {
oneDPix[cnt] = ((data[row][col][0] << 24) & 0xFF000000)
| ((data[row][col][1] << 16) & 0x00FF0000)
| ((data[row][col][2] << 8) & 0x0000FF00)
| ((data[row][col][3]) & 0x000000FF);
cnt++;
}// end for loop on col
}// end for loop on row
return oneDPix;
}// end convertToOneDim
private static double [][][] processOneToThreeDeminsion(int[] oneDPix2, int imgRows, int imgCols) {
double[][][] tempData = new double[imgRows][imgCols][4];
for(int row=0; row<imgRows; row++) {
// per row processing
int[] aRow = new int[imgCols];
for (int col = 0; col < imgCols; col++) {
int element = row * imgCols + col;
aRow[col] = oneDPix2[element];
}
// convert to three dimension data
for(int col=0; col<imgCols; col++) {
tempData[row][col][0] = (aRow[col] >> 24) & 0xFF; // alpha
tempData[row][col][1] = (aRow[col] >> 16) & 0xFF; // red
tempData[row][col][2] = (aRow[col] >> 8) & 0xFF; // green
tempData[row][col][3] = (aRow[col]) & 0xFF; // blue
}
}
return tempData;
}
public static void main(String args[]) throws IOException {
BufferedImage img = ImageIO.read(new File("E:\\test\\123.jpg"));
int imageType = img.getType();
int w = img.getWidth();
int h = img.getHeight();
int[] pix = new int[w*h];
pix = img.getRGB(0, 0, w, h, pix, 0, w);
int targetW=w*10;
int targetH=h*10;
int[] newArray =imgScale(pix, w, h, targetW, targetH);
System.out.println(imageType);
File out = new File("e:\\abc.jpg");
if (!out.exists())
out.createNewFile();
OutputStream output = new FileOutputStream(out);
BufferedImage imgOut = new BufferedImage(targetW, targetH, imageType);
imgOut.setRGB(0, 0, targetW, targetH, newArray, 0, targetW);
ImageIO.write(imgOut, "jpg", output);
}
}

下面是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
package com.util;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
public class ztest{
public static void main(String[] args) {
reduceImg("e:\\1.jpg", "e:\\test\\123.jpg",10);
}
public static void reduceImg(String imgsrc, String imgdist,int times) {
try {
File srcfile = new File(imgsrc);
if (!srcfile.exists()) {
return;
}
Image src = javax.imageio.ImageIO.read(srcfile);
BufferedImage img = ImageIO.read(new File(imgsrc));
int distW=img.getWidth()/times;
int distH=img.getHeight()/times;
System.out.println(distW);
System.out.println(distH);
BufferedImage tag= new BufferedImage( distW, distH,img.getType());
//image.SCALE_SMOOTH //平滑优先
//image.SCALE_FAST//速度优先
// image.SCALE_AREA_AVERAGING //区域均值
// image.SCALE_REPLICATE //像素复制型缩放
// image.SCALE_DEFAULT //默认缩放模式
tag.getGraphics().drawImage(src.getScaledInstance(distW, distH, Image.SCALE_SMOOTH), 0, 0, null);
FileOutputStream out = new FileOutputStream(imgdist);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(tag);
out.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

jekins是 可以用svn cvs 等 部署到远程服务器的工具 很方便 以及shell 重启tomcat容器的注意事项 费老劲了。。。。。。。。。才找到
部署什么的 很简单大家应该都明白

1去官网下个war

2 ubuntu

1
2
3
4
wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
sudo apt-get update
sudo apt-get install jenkins

jekins 的主目录是/var/lib/jenkins

下面的workspace 是他默认的checkdown目录

安装后会默认启动

如果想改端口那么更改/etc/init.d/jenkins.sh 里面的8080端口就行

启动起来后 去系统设置里面设置svn版本和地址 账户名密码 jdk

然后新建项目

注意Item名称 就是你后来checkdown下来workspace下的文件夹名称(最好别中文)

然后下一步 进入配置项目的 页面

丢弃旧的构建 选上(多少天自己设置)

源码管理 选 Subversion

Repository URL 填写自己的svn地址
Local module directory (optional) 这个是 /workspace/XXXXX/检出的代码 (其中的XXXX)
没说的 默认

构建触发器 选择Poll SCM 当svn有提交的时候 构建

             时间间隔 15 * * * *
去抓取svn更新记录的时间间隔    15分钟 后面依次是 小时 天 月 年                                                       

在最下面 你会看到增加构建步骤

选择 execute shell 然后填入 想要 在构建后执行的 linux脚本 命令
比如 ant后 移动war包 然后 重启tomcat

   ant

BUILD_ID=656412

/opt/temp/tomcat/bin/shutdown.sh

rm -rf /opt/temp/tomcat/webapps/ROOT

cp -f MobileServer.war /opt/temp/tomcat/webapps/ROOT.war

sleep 5

/opt/temp/tomcat/bin/startup.sh

需要注意 build_id 随便填 中间需要睡眠5秒 这样才能执行成功 启动tomcat命令

在tomcat里conf下的tomcat-users.xml 需要开启命令操作tomcat

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
<role rolename="admin-gui"/>
<role rolename="admin-script"/>
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<role rolename="manager-jmx"/>
<role rolename="manager-status"/>
<user username="admin" password="admin" roles="manager-gui,manager-script,manager-jmx,manager-status,admin-script,admin-gui"/>
最后 献上 ant 的build.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- 定义一个工程,默认任务为warFile。 -->
<project name="MobileServer" default="warFile" basedir=".">
<!-- 导入配置信息-->
<property file="build.properties"/>
<!-- 项目名称 -->
<property name="webapp" value="${webapp.name}"/>
<!-- 定义属性,打成war包的名称。 -->
<property name="warFileName" value="${web.war}"/>
<!-- tomcat配置信息 -->
<property name="tomcat-home" value="${tomcat.home}"/>
<property name="remote-url" value="${tomcat.url}"/>
<property name="username" value="${tomcat.username}"/>
<property name="password" value="${tomcat.password}"/>
<property name="path" value="${tomcat.context}"/>
<path id="catalina-ant-classpath">
<fileset dir="${tomcat.home}/lib">
<include name="catalina-ant.jar"/>
<include name="tomcat-coyote.jar"/>
<include name="tomcat-util.jar"/>
</fileset>
<fileset dir="${tomcat.home}/bin">
<include name="tomcat-juli.jar"/>
</fileset>
</path>
<!-- 定义路径,编译java文件时用到的jar包。 -->
<path id="project-classpath">
<fileset dir="WebRoot/WEB-INF/lib" includes="*.jar" />
<fileset dir="${tomcat-home}/lib" includes="*.jar" />
</path>
<!-- Configure the custom Ant tasks for the Manager application -->
<target name="_def_tomcat_tasks">
<!-- tasks: deploy,undeploy,reload,stop,start,list,roles,resources -->
<taskdef name="deploy"classname="org.apache.catalina.ant.DeployTask" classpathref="catalina-ant-classpath"/>
<taskdef name="list" classname="org.apache.catalina.ant.ListTask" classpathref="catalina-ant-classpath"/>
<taskdef name="reload"classname="org.apache.catalina.ant.ReloadTask" classpathref="catalina-ant-classpath"/>
<taskdef name="resources" classname="org.apache.catalina.ant.ResourcesTask" classpathref="catalina-ant-classpath"/>
<!-- <taskdef name="roles" classname="org.apache.catalina.ant.RolesTask" classpathref="catalina-ant-classpath"/> -->
<taskdef name="start" classname="org.apache.catalina.ant.StartTask" classpathref="catalina-ant-classpath"/>
<taskdef name="stop" classname="org.apache.catalina.ant.StopTask" classpathref="catalina-ant-classpath"/>
<taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask" classpathref="catalina-ant-classpath"/>
</target>
<!-- 定义任务,清空任务:清空原有的class文件,创建新的build路径。 -->
<target name="clean">
<delete dir="${basedir}/build" />
<mkdir dir="${basedir}/build" />
</target>
<!-- 定义任务,编译src文件夹中的java文件,编译后的class文件放到创建的文件夹下。 -->
<target name="compile" depends="clean">
<javac srcdir="${basedir}/src" destdir="${basedir}/build" includeantruntime="false" encoding="utf-8" debug="on" >
<classpath refid="project-classpath">
</classpath>
</javac>
</target>
<!-- 定义默认任务,将class文件集合成jar包。 -->
<target name="warFile" depends="compile">
<!-- 删除原有war包。 -->
<echo message="delete ${basedir}/${warFileName}"/>
<delete dir="${basedir}/${warFileName}" />
<echo message="delete classes"/>
<delete dir="${basedir}/WebRoot/WEB-INF/classes"/>
<echo message="create classes"/>
<mkdir dir="${basedir}/WebRoot/WEB-INF/classes"/>
<echo message="copy config.xml"/>
<copy todir="${basedir}/WebRoot/WEB-INF/classes">
<fileset dir="${basedir}/src">
<include name="**/*.xml" />
<include name="**/*.properties" />
<exclude name="**/*.java"/>
</fileset>
</copy>
<!-- 建立新war包。 -->
<war destfile="${basedir}/${warFileName}" webxml="${basedir}/WebRoot/WEB-INF/web.xml">
<!-- 将非jar和非class文件拷贝到war包的对应路径下。 -->
<fileset dir="${basedir}/WebRoot">
<include name="**/**.*" />
<exclude name="**/*.jar"/>
<exclude name="**/*.class"/>
</fileset>
<!-- 将jar和class文件拷贝到war包的对应路径下。 -->
<lib dir="${basedir}/WebRoot/WEB-INF/lib" />
<classes dir="${basedir}/build" />
</war>
</target>
<target name="list" description="List Tomcat applications">
<list url="${remote-url}"
username="${username}"
password="${password}"/>
</target>
<target name="redeploy" description="Remove and Install web application" depends="_def_tomcat_tasks">
<antcall target="stop"/>
<antcall target="undeploy"/>
<antcall target="deploy"/>
</target>
<target name="deploy" description="Install web application" depends="_def_tomcat_tasks,warFile">
<echo message="${remote-url}"/>
<echo message="${username}"/>
<echo message="${password}"/>
<echo message="${warFileName}"/>
<deploy url="${remote-url}" username="${username}" password="${password}" path="${path}" war="${warFileName}" update="true" />
</target>
<target name="undeploy" description="Remove web application" depends="_def_tomcat_tasks">
<undeploy url="${remote-url}" username="${username}" password="${password}" path="${path}" />
</target>
<target name="reload" description="Reload web application" depends="_def_tomcat_tasks">
<echo message="reload" />
<reload url="${remote-url}" username="${username}" password="${password}" path="${path}"/>
</target>
<target name="stop" description="stop web application" depends="_def_tomcat_tasks">
<echo message="stop" />
<stop url="${remote-url}" username="${username}" password="${password}" path="${path}"/>
</target>
</project>

别忘了 javac标签里的 debug=”on”
只有这样 才能 让spring mvc的注解参数 省略@标签(模拟在eclipse里 编译) 否则报错

build.properties

webapp.name=MobileServer
web.root=web
web.war=MobileServer.war
increment.file=patch.txt

javac.debuglevel=source,lines,vars
javac.target=1.6
javac.source=1.6
javac.debug=true

tomcat.home=/opt/temp/tomcat
tomcat.url=http://192.168.1.250:8888/manager/text
tomcat.username=admin
tomcat.password=admin
tomcat.context=/

这里只用了ant 来编译文件 至于那个delpoy 不好使 不知道为什么 总报错 所以才决定用 shell脚本去重启的 ant以后研究

还有一种决绝方案 就是 提交编译后的class文件 那么 jenkins 就会连同编译后的文件 一起部署了

这里要感谢 安明 童鞋的 ant支持 哇咔咔