20252 月11
@Column
@ColDefine(customType = "GEOGRAPHY(Point,4326)", adaptor = PsqlPointAdaptor.class)
@ApiModelProperty(description = "坐标")
private String geomPoint;//值格式为"POINT(经度 纬度)"
import net.postgis.jdbc.PGgeometry;
import net.postgis.jdbc.geometry.Point;
import org.nutz.dao.jdbc.ValueAdaptor;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
public class PsqlPointAdaptor implements ValueAdaptor {
@Override
public Object get(ResultSet rs, String colName) throws SQLException {
return rs.getObject(colName);
}
@Override
public void set(PreparedStatement stat, Object obj, int index) throws SQLException{
if (null == obj) {
stat.setNull(index, Types.NULL);
} else {
String pointStr = (String) obj;
Point point = new Point(pointStr);
PGgeometry pgGeometry = new PGgeometry(point);
stat.setObject(index, pgGeometry, Types.OTHER);
}
}
}
<properties>
<postgis-jdbc.version>2024.1.0</postgis-jdbc.version>
</properties>
<dependencies>
<!-- PostGIS扩展类型 -->
<dependency>
<groupId>net.postgis</groupId>
<artifactId>postgis-jdbc</artifactId>
<version>${postgis-jdbc.version}</version>
</dependency>
202411 月29
以下以Nutz代码为例:
Header header = Header.create();
header.addv("Content-Type", "application/json");
header.addv("AppCode", appcode);
Request request = Request.create(url, Request.METHOD.POST);
NutMap body = NutMap.NEW();
body.put("kssj", kssj);
body.put("jssj", jssj);
request.setHeader(header);
request.setData(Json.toJson(body));
Sender sender = Sender.create(request).setTimeout(30 * 1000);
if (url.startsWith("https")) {
try {
SSLContext sslcontext = this.createIgnoreVerifySSL();
sender.setSSLSocketFactory(sslcontext.getSocketFactory());
sender.setHostnameVerifier((urlHostName, session) -> true);
} catch (Exception e) {
e.printStackTrace();
}
}
Response response = sender.send();
if (response.isOK()) {
//todo
}
private static class TrustAllManager
implements X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
}
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
}
}
public SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new CityLifelineServer.TrustAllManager()}, null);
return sc;
}
20238 月10
@IocBean
@Slf4j
public class CimApiServer {
@Inject
private RedisService redisService;
private String redis_key = "cim:accessToken";
@Inject
@Reference(check = false)
private ISysConfigProvider sysConfigProvider;
public String getAccessToken() {
String token = redisService.get(redis_key);
if (Strings.isBlank(token)) {
token = this.getHttpToken();
redisService.setex(redis_key, 3600 * 24 - 100, token);
}
return token;
}
private String getHttpToken() {
String CIM_GIS_APPID = sysConfigProvider.getString("COMMON", "CIM_GIS_APPID");
String CIM_GIS_HTTP_BASE = sysConfigProvider.getString("COMMON", "CIM_GIS_HTTP_BASE");
String CIM_GIS_APPKEY = sysConfigProvider.getString("COMMON", "CIM_GIS_APPKEY");
String CIM_GIS_APPSECRET = sysConfigProvider.getString("COMMON", "CIM_GIS_APPSECRET");
Map<String, Object> params = new HashMap<>();
params.put("apiKey", CIM_GIS_APPKEY);
params.put("secret", CIM_GIS_APPSECRET);
Header header = Header.create();
header.addv("Content-Type", "application/json");
Request request = Request.create(CIM_GIS_HTTP_BASE + "/auth/getAccessToken", Request.METHOD.POST);
request.setHeader(header);
request.setData(Json.toJson(params));
Sender sender = Sender.create(request).setTimeout(20 * 1000);
if (CIM_GIS_HTTP_BASE.startsWith("https")) {
try {
SSLContext sslcontext = createIgnoreVerifySSL();
sender.setSSLSocketFactory(sslcontext.getSocketFactory());
sender.setHostnameVerifier((urlHostName, session) -> true);
} catch (Exception e) {
e.printStackTrace();
}
}
Response response = sender.send();
if (response.isOK()) {
NutMap map = Json.fromJson(NutMap.class, response.getContent());
log.debug("getHttpToken:::" + Json.toJson(map));
if (0 == map.getInt("code")) {
return map.getString("data");
}
}
return "";
}
private static class TrustAllManager
implements X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
}
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
}
}
public SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new TrustAllManager()}, null);
return sc;
}
}
20198 月2
项目介绍:
NutzWk 是有五年多历史的Java Web开源开发框架,其5.x 是Java 微服务分布式版本,采用nutzboot(nutz核心)、dubbo、redis、zookeeper、shiro、quartz、beetl、logback、vue、sentinel(流控框架,可选)、seata(分布式事务,可选) 等开源技术的微服务分布式版本,自带系统管理、简易CMS、微信模块、定时任务、服务API等功能,目前已应用于全国各地上千个各类商业项目中。
演示地址(Vue版本): https://nutzwk.wizzer.cn
后端技术架构:nutzboot(国产,基于国产nutz) + dubbo(国产) + redis + zookeeper + shiro + quartz + logback 等主流技术
前端技术架构:vue+ element
NutzWk v5.2.6 更新内容:
- 修改错误页机制,将前后台404/403/505 错误页严格区分;
- 修改POJO类,引入 @PrevInsert 注解,在执行fastInsert数据快速入库时有效;
- 修改web项目,Globals类 Map 对象改为 NutMap 方便开发;
- 修改vue后台,系统管理中的页面弹出框,改为手动关闭;
- 修复vue后台,数据字典管理的排序问题;
- 其他功能的完善,vue页面优化等;
- 相关jar包及第三方依赖的版本升级;
NutzWk v5.2.6-mini 版本发布:
- 具有v5.2.6 全部功能的微服务mini版本(系统管理/CMS管理/微信管理/API接口等功能齐全);
- 管理后台 vue + element;
- 非分布式,一个jar包即可运行(无dubbo依赖、无需zookepper,只需安装数据库+redis);
- 非常适合小型项目快速开发;
20186 月9
NutzWk 5.x 已发布一段时间,这段时间基于此版本开发了智慧水务系统(NB-IOT)、某物联网平台、某设备租赁平台、某智慧睡眠平台、某智慧园区项目等,开发和部署过程中遇到一些小问题,开这个帖子把一些经验分享出来省的大家走弯路。
项目地址1: https://github.com/Wizzercn/NutzWk
项目地址2: https://gitee.com/wizzer/NutzWk
1、运行环境
其实项目readme和wk-wiki 已经写的很清楚了,在此强调一下,不是说非这些版本不可,但对于新手来说最好版本号保持一致,能跑起来了您再折腾玩~~
JDK 8 162 +
Maven 3.5.3 +
Redis 4.0.8 +
MySql 5.7 +
Zookeeper 3.4.11 +
2、开发环境
一般建议使用IDEA进行开发,因为是maven多模块的项目,直接用IDEA打开项目根目录,它会通过maven下载jar包,自动构建项目
然后如何启动项目呢,有很多种方式,简单说几个:
1)打开每个NB项目(nutzboot简称)项目里的main类,右击运行,例如 cn.wizzer.sys.commons.core.***MainLauncher
2)通过IDEA 的Run 配置 Application 运行,详见 https://github.com/Wizzercn/NutzWk/blob/nutzboot-dubbo/wk-wiki/01.QuickStart/01.02.Start.md
3)命令行在NB项目根目录运行mvn compile nutzboot:run 或者IDEA右侧Maven管理界面里通过插件运行,,详见 https://github.com/nutzam/nutzboot-maven-plugin
3、启动顺序
保证MySQL、Redis、Zookeeper 都正常启动且为默认端口及默认配置(当然这些配置项可以在application.properties 修改的)
1)MySQL创建一个空白数据库,编码格式为UTF-8,数据库名称 nutzwk_nb
2)NB项目的模块启动顺序是 sys –> cms[可选] –> wx[可选] –> task[可选] –> web-platform –> web-api[可选]
3)如上所述,如果想运行访问后台,只需要启动 sys 和 web-platform即可,注意是有启动顺序的,其他模块需要用就启
4)task 定时任务是依赖于sys的,而web-platform系统管理对定时任务管理是依赖于 task模块的,如果你想让task独立运行并且不需要通过页面进行管理,自己少做改动即可,不是不可以哦
4、部署注意事项
1)因为登录页面对密码进行了RSA加密,有时候部署会遇到怎么也登录不了,而后台抛异常 java.lang.SecurityException: JCE cannot authenticate the provider BC 的情况,解决方法在代码注释里已写明了,不过很少有人去看
https://github.com/Wizzercn/NutzWk/blob/nutzboot-dubbo/wk-app/wk-nb-web-platform/src/main/java/cn/wizzer/app/web/commons/shiro/filter/PlatformAuthenticationFilter.java
1、编辑文件 /usr/java/jdk1.8.0_162/jre/lib/security/java.security
在9下面添加 security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider
2、拷贝 bcprov-jdk16-143.jar 和 bcprov-jdk15-135.jar 到 /usr/java/jdk1.8.0_162/jre/lib/ext 目录下
3、别问我上面两个文件怎么找……
(如果您是https的话可以把RSA加密方式改掉弃用哦)
2)服务器注意事项:服务器时间同步做没做、hosts里配没配主机名hostname和127.0.0.1的映射关系、内存够不够用(有没有给jar指定内存大小)等
5、其他
1)请关注 NutzWk 的动态,有新的版本发布建议及时更新,往往会修复问题或新增功能
2)如果 NutzWk 给了您帮助,或已用于生产, https://wizzer.cn/donation 欢迎打赏一定金额以资鼓励,创造国内良好的开源环境
3)最后感谢兽兽及nutz社区广大网友的帮助和鼓励,没有您们的支持,这个项目不会历经6年多还在更新前进
20182 月26

1、MainServer 启动类
/**
* Created by Wizzer on 2018/2/26.
*/
@IocBean
public class MainServer {
private static final Log log = Logs.get();
public static void main(String[] args) {
try {
ComboIocLoader loader = new ComboIocLoader(
new String[]{"*json", "config/ioc/", "*anno", "cn.wizzer","*rabbitmq"}
);
NutIoc ioc = new NutIoc(loader);
//socket
ioc.get(SocketServer.class).init();
//http
ioc.get(HttpServer.class).init();
//mq
String topicQueue = "sweeper-tioTopicQueue";
ConnectionFactory factory = ioc.get(ConnectionFactory.class, "rabbitmq_cf");
Connection rabbitmq_conn = factory.newConnection();
Channel rabbitmq_channel = rabbitmq_conn.createChannel();
rabbitmq_channel.queueDeclare(topicQueue, true, false, false, null);
rabbitmq_channel.exchangeDeclare("sweeper-tioTopicExchange", BuiltinExchangeType.TOPIC, true);
rabbitmq_channel.queueBind(topicQueue, "sweeper-tioTopicExchange", "tio.#");
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、SocketServer 数据接收
/**
* Created by Wizzer on 2018/2/26.
*/
@IocBean
public class SocketServer {
private static final Log log = Logs.get();
//handler, 包括编码、解码、消息处理
@Inject
private MyServerAioHandler myServerAioHandler;
//事件监听器,可以为null,但建议自己实现该接口,可以参考showcase了解些接口
private ServerAioListener aioListener;
//一组连接共用的上下文对象
private ServerGroupContext serverGroupContext;
//aioServer对象
private AioServer aioServer;
//有时候需要绑定ip,不需要则null
private String serverIp;
@Inject
private PropertiesProxy conf;
public void init() throws Exception {
int port = conf.getInt("server.socket.port", 8600);
log.debug("socket port::" + port);
serverGroupContext = new ServerGroupContext("tio", myServerAioHandler, aioListener);
serverGroupContext.setHeartbeatTimeout(30000);
aioServer = new AioServer(serverGroupContext);
aioServer.start(serverIp, port);
}
}
3、socket 数据包的解析
4、RabbitMQ 队列+消费者 实现数据入库
5、HttpServer 提供HTTP API用于对设备发送命令
6、socket 命令包的下发
源码:https://gitee.com/wizzer/demo
20181 月21
后台代码,自定义tag:
package cn.wizzer.app.web.modules.tags;
import cn.wizzer.app.web.commons.ex.elasticsearch.EsService;
import cn.wizzer.app.web.commons.utils.YcDateUtil;
import cn.wizzer.app.ycold.modules.services.YcoldInquiryService;
import cn.wizzer.framework.page.Pagination;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.beetl.core.GeneralVarTagBinding;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* Created by wizzer on 2018/1/20.
*/
@IocBean
public class YcoldInquiryListTag extends GeneralVarTagBinding {
private final static Log log = Logs.get();
@Inject
private EsService esService;
@Inject
private YcoldInquiryService ycoldInquiryService;
@Inject
private PropertiesProxy cfg;
@Override
public void render() {
String startDate = Strings.sNull(this.getAttributeValue("startDate"));
String endDate = Strings.sNull(this.getAttributeValue("endDate"));
String keyword = Strings.sNull(this.getAttributeValue("keyword"));
int pageNumber = NumberUtils.toInt(Strings.sNull(this.getAttributeValue("pageNumber")), 1);
int pageSize = NumberUtils.toInt(Strings.sNull(this.getAttributeValue("pageSize")), 10);
boolean highlight = BooleanUtils.toBoolean(Strings.sNull(this.getAttributeValue("highlight")));
boolean explain = BooleanUtils.toBoolean(Strings.sNull(this.getAttributeValue("explain")));
String sortName = Strings.sNull(this.getAttributeValue("sortName"));
String sortOrder = Strings.sNull(this.getAttributeValue("sortOrder"));
Pagination page = new Pagination();
page.setPageNo(pageNumber);
page.setPageSize(pageSize);
try {
BoolQueryBuilder query = QueryBuilders.boolQuery();
//根据名称查询
if (Strings.isNotBlank(keyword)) {
query.must(QueryBuilders.wildcardQuery("CASNM", "*" + keyword + "*"));
}
//截止时间大于等于现在
query.must(QueryBuilders.rangeQuery("IQDAT").gte(Times.format("yyyyMMddHHmmss", new Date())));
//公共日期起
if (Strings.isNotBlank(startDate)) {
query.must(QueryBuilders.rangeQuery("ANNODAT").gte(startDate.replaceAll("-","")));
}
//公共日期至
if (Strings.isNotBlank(endDate)) {
query.must(QueryBuilders.rangeQuery("ANNODAT").lte(endDate.replaceAll("-","")));
}
//几个状态条件
query.must(QueryBuilders.matchQuery("BUYER_STS", "N"));//采购商状态
query.must(QueryBuilders.matchQuery("STS", "A"));//状态
query.must(QueryBuilders.matchQuery("ANNOMK", "Y"));//公告註記
SearchRequestBuilder srb = esService.getClient().prepareSearch(cfg.get("es.index.name"))
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setTypes("inquiry")
.setQuery(query)
//分页
.setFrom((pageNumber - 1) * pageSize).setSize(pageSize)
//是否按匹配度排序
.setExplain(explain);
if (highlight) {
HighlightBuilder highlightBuilder = new HighlightBuilder().field("*").requireFieldMatch(false);
highlightBuilder.preTags("<span style=\"color:red\">");
highlightBuilder.postTags("</span>");
srb.highlighter(highlightBuilder);
}
if (Strings.isNotBlank(sortName)) {
String[] sortNames = StringUtils.split(sortName, ",");
if ("asc".equalsIgnoreCase(sortOrder)) {
for (String s : sortNames) {
srb.addSort(s, SortOrder.ASC);
}
} else {
for (String s : sortNames) {
srb.addSort(s, SortOrder.DESC);
}
}
}
log.debug("srb:::\r\n" + srb.toString());
SearchResponse response = srb.execute().actionGet();
SearchHits hits = response.getHits();
page.setTotalCount((int) hits.getTotalHits());
List<Map<String, Object>> list = new ArrayList<>();
hits.forEach(searchHit -> {
Map<String, Object> source = searchHit.getSourceAsMap();
Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
//name高亮
HighlightField nameField = highlightFields.get("CASNM");
if (nameField != null) {
Text[] fragments = nameField.fragments();
String tmp = "";
for (Text text : fragments) {
tmp += text;
}
source.put("CASNM", tmp);
}
source.put("IQDAT", YcDateUtil.get_yyyyMMdd_HHmm(Strings.sNull(source.get("IQDAT"))));
source.put("ANNODAT", YcDateUtil.get_yyyyMMdd(Strings.sNull(source.get("ANNODAT"))));
list.add(source);
});
page.setList(list);
} catch (Exception e) {
e.printStackTrace();
}
this.binds(page);
this.doBodyRender();
}
}
前台beetl页面:
<#ycold_inquiry_list pageNumber="${pageNumber}" pageSize="${pageSize}" startDate="${startDate}" endDate="${endDate}" keyword="${keyword}" sortName="ANNODAT" sortOrder="desc" highlight="false" var="p">
<table class="list_table_blue even_table">
<thead>
<tr>
<th>公告日期</th>
<th>案件名称</th>
<th>交货地点</th>
<th>报价截止日期</th>
<th width="110">查看详细</th>
</tr>
</thead>
<tbody>
<%for(o in p.list){%>
<tr>
<td>${o.ANNODAT!}</td>
<td class="l_text"><a href="${base!}/purchase/info/${o.XUID!}" target="_blank" class="td_a hide1">${o.CASNM!}</a>
</td>
<td class="l_text">${o.DLSITE!}</td>
<td>${o.IQDAT!}</td>
<td><a href="${base!}/purchase/info/${o.XUID!}" target="_blank" class="more_a png"></a></td>
</tr>
<%}%>
</tbody>
</table>
<%if(p.totalCount>1){%>
<div class="page round_s_a"></div>
<script type="text/javascript">
$(function () {
$(".page").createPage({
pageCount: ${p.totalPage},
totalCount: ${p.totalCount},
current: ${p.pageNo},
backFn: function (p) {
window.location.href = "?page=" + p + "&size=${p.pageSize}";
}
});
});
</script>
<%}%>
20181 月21
if (!esService.isExistsType(cfg.get("es.index.name"), type)) {
//初始化索引表
XContentBuilder mapping = jsonBuilder().startObject()
.startObject(type)
.startObject("_all")//设置IK分词
.field("analyzer", "ik_max_word")
.field("search_analyzer", "ik_max_word")
.field("term_vector", "no")
.field("store", "false")
.endObject()
.startObject("properties")
.startObject("CASNM").field("type", "text").field("analyzer", "ik_max_word").endObject()
.startObject("IQDAT").field("type", "text").field("index", "true").field("fielddata","true").endObject()
.startObject("ANNODAT").field("type", "text").field("index", "true").field("fielddata","true").endObject()
.endObject()
.endObject()
.endObject();
esService.putMapping(cfg.get("es.index.name"), "inquiry", mapping);
}
/**
* @param indexName 索引名
* @param type 数据类型(表名)
* @param mapping mapping对象
*/
public boolean putMapping(String indexName, String type, XContentBuilder mapping) {
PutMappingRequest mappingRequest = Requests.putMappingRequest(indexName).type(type).source(mapping);
PutMappingResponse response = getClient().admin().indices().putMapping(mappingRequest).actionGet();
return response.isAcknowledged();
}
.field(“fielddata”,”true”) //text字段默认不允许排序,是单独设置数据格式
20173 月23
1、wx_config 实体类添加三个字段,对应的表结构也要手动修改:
@Column
@Comment("access_token")
@ColDefine(type = ColType.VARCHAR, width = 255)
private String access_token;
@Column
@Comment("access_token_expires")
@ColDefine(type = ColType.INT)
private Integer access_token_expires;
@Column
@Comment("access_token_lastat")
@ColDefine(type = ColType.VARCHAR, width = 50)
private String access_token_lastat;
get set ...方法生成出来
2、nutzwx版本升级为1.r.61-SNAPSHOT
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzwx</artifactId>
<version>1.r.61-SNAPSHOT</version>
</dependency>
3、nutz版本升级为1.r.60
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutz</artifactId>
<version>1.r.60</version>
</dependency>
4、WxConfigService 类getWxApi2替换为如下代码(主要是DaoAccessTokenStore从数据库取access_token)
public WxApi2 getWxApi2(String wxid) {
Wx_config appInfo = this.fetch(Cnd.where("id", "=", wxid));
DaoAccessTokenStore myDaoAccessTokenStore = new DaoAccessTokenStore(dao());
Map<String, Object> params = new HashMap<>();
params.put("id", appInfo.getId());
myDaoAccessTokenStore.setTableAccessToken("access_token");
myDaoAccessTokenStore.setTableAccessTokenExpires("access_token_expires");
myDaoAccessTokenStore.setTableAccessTokenLastat("access_token_lastat");
myDaoAccessTokenStore.setFetch("select access_token,access_token_expires,access_token_lastat from wx_config where id=@id");
myDaoAccessTokenStore.setUpdate("update wx_config set access_token=@access_token, access_token_expires=@access_token_expires, access_token_lastat=@access_token_lastat where id=@id");
myDaoAccessTokenStore.setParams(params);
WxApi2Impl wxApi2 = new WxApi2Impl();
wxApi2.setAppid(appInfo.getAppid());
wxApi2.setAppsecret(appInfo.getAppsecret());
wxApi2.setEncodingAesKey(appInfo.getEncodingAESKey());
wxApi2.setToken(appInfo.getToken());
wxApi2.setAccessTokenStore(myDaoAccessTokenStore);
return wxApi2;
}
201612 月8
Cnd cnd = Cnd.NEW();
if (!Strings.isBlank(src)) {
cnd.and("srcFrom", "=", src);
}
if (!Strings.isBlank(name)) {
String[] n = StringUtils.split(name, " ");
SqlExpressionGroup group = new SqlExpressionGroup();
for (String s : n) {
SqlExpression sqlExpression = Cnd.exp("srcName", "like", "%" + s + "%");
group.or(sqlExpression);
}
cnd.and(group);
}
cnd.and(Cnd.exps("productSku", "=", "").or("productSku", "is", null));
201610 月20
Shop_goods_type obj = shopGoodsTypeService.fetch(id);
shopGoodsTypeService.fetchLinks(obj, null, Cnd.orderBy().asc("location"));
for (Shop_goods_type_props o : obj.getPropsList()) {
shopGoodsTypeService.dao().fetchLinks(o, null, Cnd.orderBy().asc("location"));
}
20156 月11
pom.xml
<!--CXF START-->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-api</artifactId>
<version>2.7.15</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>2.7.15</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-bindings-soap</artifactId>
<version>2.7.15</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>2.7.15</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-security</artifactId>
<version>2.7.15</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.5.RELEASE</version>
</dependency>
<!--CXF END-->
web.xml
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/webservice/*</url-pattern>
</servlet-mapping>
cxf-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:soap="http://cxf.apache.org/bindings/soap"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<!-- IP地址输入拦截器 -->
<bean id="ipAddressInInterceptor"
class="com.auto.webservice.servlet.IpAddressInInterceptor" />
<jaxws:server id="workflow" serviceClass="com.auto.webservice.server.WorkflowService" address="/workflow">
<jaxws:serviceBean>
<bean class="com.auto.webservice.server.WorkflowServiceImpl" />
</jaxws:serviceBean>
</jaxws:server>
</beans>
接口类
WorkflowService.java
package com.auto.webservice.server;
import org.nutz.json.Json;
import javax.jws.WebService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by wizzer on 15-4-13.
*/
@WebService(targetNamespace = "http://server.webservice.auto.com/", name = "workflowServicePortType")
public interface WorkflowService {
@WebResult(name = "return")
@Action(input = "urn:start", output = "urn:startResponse")
@RequestWrapper(localName = "start")
@WebMethod(action = "urn:start")
@ResponseWrapper(localName = "startResponse")
String start(@WebParam(name = "flowKey") String flowKey, @WebParam(name = "userId") String userId);//启动流程
}
实现类
WorkflowServiceImpl.java
package com.auto.webservice.server;
import org.activiti.engine.*;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.form.StartFormData;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.json.JsonFormat;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;
import javax.jws.WebService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by wizzer on 15-4-13.
*/
@IocBean(name = "workflowService")
@WebService
public class WorkflowServiceImpl implements WorkflowService {
private final Log log = Logs.get();
FormService formService=Mvcs.ctx().getDefaultIoc().get(FormService.class);
IdentityService identityService=Mvcs.ctx().getDefaultIoc().get(IdentityService.class);
RuntimeService runtimeService=Mvcs.ctx().getDefaultIoc().get(RuntimeService.class);
TaskService taskService=Mvcs.ctx().getDefaultIoc().get(TaskService.class);
RepositoryService repositoryService=Mvcs.ctx().getDefaultIoc().get(RepositoryService.class);
/**
* 启动一个流程
*
* @param flowKey 流程模型key
* @param userId 用户ID
* @return
*/
public String start(String flowKey, String userId) {
Map<String, Object> map = new HashMap<String, Object>();
try {
if (!Strings.isEmpty(userId)) {
identityService.setAuthenticatedUserId(userId);
}
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(flowKey);
map.put("errcode", 0);
map.put("errmsg", "");
map.put("processInstanceId", processInstance.getId());
} catch (Exception e) {
log.error("WebServcice启动流程出错", e);
map.put("errcode", 1);
map.put("errmsg", e.getMessage());
} finally {
identityService.setAuthenticatedUserId(null);
}
return Json.toJson(map, JsonFormat.compact());
}
}
/**
* IP地址拦截器
*
* @author Sunshine
*/
public class IpAddressInInterceptor extends AbstractPhaseInterceptor {
private final Log log = Logs.get();
public IpAddressInInterceptor() {
super(Phase.RECEIVE);
}
public void handleMessage(Message message) throws Fault {
HttpServletRequest request = (HttpServletRequest) message.get(AbstractHTTPDestination.HTTP_REQUEST);
//获取所有的白名单访问主机
UserInfoServiceImpl userInfoService = Mvcs.ctx().getDefaultIoc().get(UserInfoServiceImpl.class);
List hostList = userInfoService.queryHostListByType("w");
// 取客户端IP地址
String ipAddress = request.getRemoteAddr();
// 如果允许访问的集合非空,继续处理,否则认为全部IP地址均合法
if (!hostList.isEmpty()) {
boolean contains = false;
for (ListInfo hostInfo : hostList) {
log.debug("hostInfo:" + hostInfo.getIpaddress() + "|ipAddress:" + ipAddress);
if (hostInfo.getIpaddress().equals(ipAddress)) {
contains = true;
break;
}
}
if (!contains) {
throw new Fault(new IllegalAccessException("IP address " + ipAddress + " is not allowed"));
}
}
}
}
20155 月18
@At
public String test5(@Param("taskId") String taskId) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null)
return "null";
ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(task.getProcessDefinitionId());
List<ActivityImpl> activitiList = def.getActivities();
System.out.println("getTaskDefinitionKey:::" + task.getTaskDefinitionKey());
NutMap map = new NutMap();
int type = 0;
getTaskActivitys(task.getTaskDefinitionKey(), activitiList, type, map);
return Json.toJson(map);
}
public static List<PvmActivity> getTaskActivitys(String activityId, List<ActivityImpl> activityList, int type, NutMap map) {
List<PvmActivity> activitiyIds = new ArrayList<>();
for (ActivityImpl activityImpl : activityList) {
String id = activityImpl.getId();
if (activityId.equals(id)) {
List<PvmTransition> outgoingTransitions = activityImpl.getOutgoingTransitions();//获取某节点所有线路
List<NutMap> list = new ArrayList<>();
for (PvmTransition tr : outgoingTransitions) {
NutMap map1 = new NutMap();
PvmActivity ac = tr.getDestination();//获取线路的终点节点
if (ac.getProperty("type").equals("userTask")) {
map.setv("type", type++);
map1.setv("id", ac.getId());
map1.setv("name", ac.getProperty("name"));
String conditionText=Strings.sNull(tr.getProperty("conditionText"));
if(!Strings.isEmpty(conditionText)){
map1.setv("conditionText",conditionText );
}
list.add(map1);
} else if (ac.getProperty("type").equals("exclusiveGateway")) {
getTaskActivitys(ac.getId(), activityList, type, map);
} else {
map.setv("type", type++);
break;
}
}
if (list.size() > 0)
map.addv("list", list);
break;
}
}
return activitiyIds;
}
20155 月12
通过配置文件实现(这个支持CXF spring注解)点这里
pom.xml
<!--CXF START-->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-api</artifactId>
<version>2.7.15</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>2.7.15</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-bindings-soap</artifactId>
<version>2.7.15</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>2.7.15</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-security</artifactId>
<version>2.7.15</version>
</dependency>
<!--CXF END-->
web.xml
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>com.auto.webservice.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/webservice/*</url-pattern>
</servlet-mapping>
CXFServlet.java:
package com.auto.webservice.servlet;
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.frontend.ServerFactoryBean;
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
import org.nutz.ioc.Ioc;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;
import javax.jws.WebService;
import javax.servlet.ServletConfig;
import javax.xml.namespace.QName;
/**
* Created by wizzer on 15-4-10.
*/
@SuppressWarnings("serial")
public class CXFServlet extends CXFNonSpringServlet {
private final Log log = Logs.get();
@Override
protected void loadBus(ServletConfig sc) {
super.loadBus(sc);
//全局配置
Bus bus = getBus();
//添加白名单过滤器
bus.getInInterceptors().add(new IpAddressInInterceptor());
//使用全局配置
BusFactory.setDefaultBus(bus);
Ioc ioc = Mvcs.ctx().getDefaultIoc();
for (String name : ioc.getNames()) {
try {
Object obj = ioc.get(null, name);
if (!obj.getClass().getPackage().getName().equals("com.auto.webservice.server")) {
continue;
}
if (obj.getClass().getAnnotation(WebService.class) == null)
continue;
Class face = Class.forName(obj.getClass().getPackage().getName() + "." + Strings.upperFirst(name));
ServerFactoryBean serverFactoryBean = new ServerFactoryBean();
// 设置服务接口类
serverFactoryBean.setServiceClass(face);
// 服务请求路径
serverFactoryBean.setAddress("/" + name.substring(0, name.indexOf("Service")));
// 设置服务实现类
serverFactoryBean.setServiceBean(obj);
serverFactoryBean.setBindingId("http://schemas.xmlsoap.org/wsdl/soap12/");
serverFactoryBean.create();
} catch (Throwable e) {
}
}
}
}
接口类
WorkflowService.java
package com.auto.webservice.server;
import org.nutz.json.Json;
import javax.jws.WebService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by wizzer on 15-4-13.
*/
@WebService
public interface WorkflowService {
String start(String flowKey, String userId);//启动流程
}
实现类
WorkflowServiceImpl.java
package com.auto.webservice.server;
import org.activiti.engine.*;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.form.StartFormData;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.json.JsonFormat;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;
import javax.jws.WebService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by wizzer on 15-4-13.
*/
@IocBean(name = "workflowService")
@WebService
public class WorkflowServiceImpl implements WorkflowService {
private final Log log = Logs.get();
@Inject
Dao dao;
@Inject
FormService formService;
@Inject
IdentityService identityService;
@Inject
RepositoryService repositoryService;
@Inject
RuntimeService runtimeService;
@Inject
TaskService taskService;
/**
* 启动一个流程
*
* @param flowKey 流程模型key
* @param userId 用户ID
* @return
*/
public String start(String flowKey, String userId) {
Map<String, Object> map = new HashMap<String, Object>();
try {
if (!Strings.isEmpty(userId)) {
identityService.setAuthenticatedUserId(userId);
}
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(flowKey);
map.put("errcode", 0);
map.put("errmsg", "");
map.put("processInstanceId", processInstance.getId());
} catch (Exception e) {
log.error("WebServcice启动流程出错", e);
map.put("errcode", 1);
map.put("errmsg", e.getMessage());
} finally {
identityService.setAuthenticatedUserId(null);
}
return Json.toJson(map, JsonFormat.compact());
}
}
20155 月7
在nutz filter作用域内才能Mvcs.getIoc()
其他情况:
Mvcs.ctx().getDefaultIoc().get(xxx.class)
20154 月27
首先值得一提的是,taskService.createTaskQuery().taskCandidateOrAssigned(userId) 方法有bug,不会调用重写的工厂类,请使用taskService.createTaskQuery().taskCandidateUser(userId)方法。
CustomGroupEntityManager
/**
* 分组工厂类
* Created by wizzer on 15-4-27.
*/
@IocBean
public class CustomGroupEntityManager extends GroupEntityManager {
Dao dao= Mvcs.getIoc().get(Dao.class);
private final Log log = Logs.get();
@Override
public List<Group> findGroupsByUser(String userId) {
Sql sql = Sqls.create("SELECT a.* FROM sys_role a,sys_user_role b WHERE a.id=b.roleid AND b.userid=@c");
sql.params().set("c", userId);
sql.setCallback(Sqls.callback.maps());
dao.execute(sql);
List<Map> list=sql.getList(Map.class);
List<Group> groupList=new ArrayList<Group>();
for (Map m:list){
GroupEntity group=new GroupEntity();
group.setId(Strings.sNull(m.get("id")));
group.setName(Strings.sNull(m.get("name")));
group.setType("assignment");
group.setRevision(1);
groupList.add(group);
}
return groupList;
}
}
CustomGroupEntityManagerFactory
/**
* 分组接口类
* Created by wizzer on 15-4-27.
*/
@IocBean
public class CustomGroupEntityManagerFactory implements SessionFactory {
private GroupEntityManager groupEntityManager;
public void setGroupEntityManager(GroupEntityManager groupEntityManager) {
this.groupEntityManager = groupEntityManager;
}
@Override
public Class<?> getSessionType() {
return GroupIdentityManager.class;
}
@Override
public Session openSession() {
return groupEntityManager;
}
}
CustomUserEntityManager
/**
* 用户工厂类
* Created by wizzer on 15-4-24.
*/
@IocBean
public class CustomUserEntityManager extends UserEntityManager {
Dao dao= Mvcs.getIoc().get(Dao.class);
private final Log log = Logs.get();
@Override
public User findUserById(String userId) {
log.info("findUserById:::::::::::::::::::::::::::::::"+userId);
UserEntity userEntity = new UserEntity();
Sys_user sysUser = dao.fetch(Sys_user.class, Cnd.where("uid", "=", userId));
userEntity.setId(userId);
userEntity.setFirstName(sysUser.getRealname());
userEntity.setEmail(sysUser.getEmail());
userEntity.setRevision(1);
return userEntity;
}
@Override
public List<Group> findGroupsByUser(String userId) {
// TODO Auto-generated method stub
log.info("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
Sql sql = Sqls.create("SELECT a.* FROM sys_role a,sys_user_role b WHERE a.id=b.roleid AND b.userid=@c");
sql.params().set("c", userId);
sql.setCallback(Sqls.callback.maps());
dao.execute(sql);
List<Map> list=sql.getList(Map.class);
List<Group> groupList=new ArrayList<Group>();
for (Map m:list){
GroupEntity group=new GroupEntity();
group.setId(Strings.sNull(m.get("id")));
group.setName(Strings.sNull(m.get("name")));
group.setType("assignment");
group.setRevision(1);
groupList.add(group);
}
return groupList;
}
}
CustomUserEntityManagerFactory
/**
* 用户接口类
* Created by wizzer on 15-4-24.
*/
@IocBean
public class CustomUserEntityManagerFactory implements SessionFactory {
private UserEntityManager userEntityManager;
public void setUserEntityManager(UserEntityManager userEntityManager) {
this.userEntityManager = userEntityManager;
}
@Override
public Class<?> getSessionType() {
return UserIdentityManager.class;
}
@Override
public Session openSession() {
return userEntityManager;
}
}
在初始化activiti时追加代码:
List<SessionFactory> list=new ArrayList<SessionFactory>();
CustomGroupEntityManagerFactory customGroupManagerFactory=new CustomGroupEntityManagerFactory();
customGroupManagerFactory.setGroupEntityManager(new CustomGroupEntityManager());
CustomUserEntityManagerFactory customUserEntityManagerFactory=new CustomUserEntityManagerFactory();
customUserEntityManagerFactory.setUserEntityManager(new CustomUserEntityManager());
list.add(customGroupManagerFactory);
list.add(customUserEntityManagerFactory);
processEngineConfiguration.setCustomSessionFactories(list);
20154 月27
@SetupBy(value=StartSetup.class)
public class MainModule {
}
private void activitiInit(NutConfig config) {
log.info("Activiti Init Start...");
ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) ProcessEngineConfiguration
.createStandaloneProcessEngineConfiguration();
processEngineConfiguration.setDataSource(config.getIoc().get(DataSource.class));
processEngineConfiguration.setDatabaseSchemaUpdate("false");
processEngineConfiguration.setJobExecutorActivate(false);
processEngineConfiguration.setActivityFontName("宋体");
processEngineConfiguration.setLabelFontName("宋体");
processEngineConfiguration.setXmlEncoding("utf-8");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
((Ioc2) config.getIoc()).getIocContext().save("app", "processEngine", new ObjectProxy(processEngine));
((Ioc2) config.getIoc()).getIocContext().save("app", "repositoryService", new ObjectProxy(processEngine.getProcessEngineConfiguration().getRepositoryService()));
((Ioc2) config.getIoc()).getIocContext().save("app", "runtimeService", new ObjectProxy(processEngine.getProcessEngineConfiguration().getRuntimeService()));
((Ioc2) config.getIoc()).getIocContext().save("app", "taskService", new ObjectProxy(processEngine.getProcessEngineConfiguration().getTaskService()));
((Ioc2) config.getIoc()).getIocContext().save("app", "formService", new ObjectProxy(processEngine.getProcessEngineConfiguration().getFormService()));
((Ioc2) config.getIoc()).getIocContext().save("app", "historyService", new ObjectProxy(processEngine.getProcessEngineConfiguration().getHistoryService()));
((Ioc2) config.getIoc()).getIocContext().save("app", "managementService", new ObjectProxy(processEngine.getProcessEngineConfiguration().getManagementService()));
((Ioc2) config.getIoc()).getIocContext().save("app", "identityService", new ObjectProxy(processEngine.getProcessEngineConfiguration().getIdentityService()));
log.info("Activiti Init End.");
}
20154 月24
public String getTemplateStr(String template, Map<String, String> para) {
StringWriter writer = new StringWriter();
try {
RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
StringReader reader = new StringReader(template);
SimpleNode node = runtimeServices.parse(reader, "Template name");
Template t = new Template();
t.setRuntimeServices(runtimeServices);
t.setData(node);
t.initDocument();
VelocityContext context = new VelocityContext();
if (para.size() > 0) {
for (String key : para.keySet()) {
context.put(key, para.get(key));
}
}
t.merge(context, writer);
} catch (Exception e) {
throw new RuntimeException("Error commiting transaction! cause:"+ e.getMessage());
}
return writer.toString();
}
@At("/form")
@Ok("vm:template.private.test")
public void form(HttpServletRequest req, HttpServletResponse resp) {
Map<String, Object> formParams = new HashMap<String, Object>();
formParams.put("formKey", "form/waizhibiaodan/01/01.form");
int timeout = 60 * 1000;
String str = Http.post("http://127.0.0.1/test/getFormKey", formParams, timeout);
NutMap map = Json.fromJson(NutMap.class, str);
String formData = map.getString("data");
Map<String, String> params = new HashMap<String, String>();
params.put("startDate", "2015-04-21");
params.put("endDate", "2015-04-25");
req.setAttribute("formData", getTemplateStr(formData, params));
}
20154 月21
mvn package -Dmaven.test.skip=true