新增企业微信扫描登录
This commit is contained in:
parent
174ae785f8
commit
dbe6994d09
|
@ -8,20 +8,16 @@ import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.snow.common.constant.Constants;
|
import com.snow.common.constant.Constants;
|
||||||
import com.snow.common.enums.DingTalkListenerType;
|
import com.snow.common.enums.DingTalkListenerType;
|
||||||
import com.snow.dingtalk.common.EventNameEnum;
|
|
||||||
import com.snow.dingtalk.sync.ISyncSysInfo;
|
import com.snow.dingtalk.sync.ISyncSysInfo;
|
||||||
import com.snow.dingtalk.sync.SyncSysInfoFactory;
|
import com.snow.dingtalk.sync.SyncSysInfoFactory;
|
||||||
import com.snow.system.domain.DingtalkCallBack;
|
import com.snow.system.domain.DingtalkCallBack;
|
||||||
import com.snow.system.service.impl.DingtalkCallBackServiceImpl;
|
import com.snow.system.service.impl.DingtalkCallBackServiceImpl;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.crypto.Mac;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -97,6 +93,8 @@ public class CallBackController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接收钉钉dingFlow机器人消息
|
* 接收钉钉dingFlow机器人消息
|
||||||
* @return
|
* @return
|
||||||
|
|
|
@ -1,36 +1,25 @@
|
||||||
package com.snow.web.controller.dingtalk;
|
package com.snow.web.controller.dingtalk;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.dingtalk.api.response.OapiSnsGetuserinfoBycodeResponse;
|
|
||||||
import com.dingtalk.api.response.OapiUserGetbyunionidResponse;
|
|
||||||
import com.dingtalk.api.response.OapiV2UserGetResponse;
|
|
||||||
import com.snow.common.core.controller.BaseController;
|
import com.snow.common.core.controller.BaseController;
|
||||||
import com.snow.common.core.domain.AjaxResult;
|
import com.snow.common.core.domain.AjaxResult;
|
||||||
import com.snow.common.utils.AuthUtils;
|
|
||||||
import com.snow.common.utils.ServletUtils;
|
import com.snow.common.utils.ServletUtils;
|
||||||
import com.snow.common.utils.StringUtils;
|
import com.snow.common.utils.StringUtils;
|
||||||
import com.snow.dingtalk.service.UserService;
|
|
||||||
import com.snow.framework.shiro.auth.LoginType;
|
import com.snow.framework.shiro.auth.LoginType;
|
||||||
import com.snow.framework.shiro.auth.UserToken;
|
import com.snow.framework.shiro.auth.UserToken;
|
||||||
import com.snow.framework.util.ShiroUtils;
|
import com.snow.framework.util.ShiroUtils;
|
||||||
import com.snow.system.domain.SysAuthUser;
|
import com.snow.system.domain.SysAuthUser;
|
||||||
import com.snow.system.domain.SysSocialUser;
|
|
||||||
import com.snow.system.domain.SysUser;
|
import com.snow.system.domain.SysUser;
|
||||||
import com.snow.system.mapper.SysUserMapper;
|
import com.snow.system.mapper.SysUserMapper;
|
||||||
import com.snow.system.service.ISysConfigService;
|
import com.snow.system.service.ISysConfigService;
|
||||||
import com.snow.system.service.impl.SysSocialUserServiceImpl;
|
|
||||||
import com.snow.system.service.impl.SysUserServiceImpl;
|
|
||||||
import me.zhyd.oauth.cache.AuthDefaultStateCache;
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
import me.zhyd.oauth.model.AuthCallback;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthResponse;
|
import me.zhyd.oauth.model.AuthResponse;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.request.AuthDingTalkRequest;
|
import me.zhyd.oauth.request.AuthDingTalkRequest;
|
||||||
import me.zhyd.oauth.request.AuthRequest;
|
import me.zhyd.oauth.request.AuthRequest;
|
||||||
|
import me.zhyd.oauth.request.AuthWeChatEnterpriseRequest;
|
||||||
import me.zhyd.oauth.utils.AuthStateUtils;
|
import me.zhyd.oauth.utils.AuthStateUtils;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.apache.shiro.authc.AuthenticationException;
|
|
||||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
|
||||||
import org.apache.shiro.subject.Subject;
|
import org.apache.shiro.subject.Subject;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
@ -40,8 +29,6 @@ import org.springframework.web.servlet.ModelAndView;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @program: snow
|
* @program: snow
|
||||||
|
@ -71,19 +58,34 @@ public class ThirdOauthController extends BaseController {
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public void renderAuth(@PathVariable("source") String source) throws IOException
|
public void renderAuth(@PathVariable("source") String source) throws IOException
|
||||||
{
|
{
|
||||||
String appId= iSysConfigService.selectConfigByKey("ding.login.appid");
|
AuthRequest authRequest =null;
|
||||||
String appSecret= iSysConfigService.selectConfigByKey("ding.login.appSecret");
|
switch (source){
|
||||||
String redirectUri= iSysConfigService.selectConfigByKey("ding.login.redirectUri");
|
case "dingtalk":
|
||||||
|
authRequest= getDingTalkAuthRequest();
|
||||||
|
break;
|
||||||
|
case "weChart":
|
||||||
|
authRequest=getWeChatAuthRequest();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
AuthRequest authRequest = new AuthDingTalkRequest(AuthConfig.builder()
|
|
||||||
.clientId(appId)
|
|
||||||
.clientSecret(appSecret)
|
|
||||||
.redirectUri(redirectUri)
|
|
||||||
.build());
|
|
||||||
String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
|
String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
|
||||||
ServletUtils.getResponse().sendRedirect(authorizeUrl);
|
ServletUtils.getResponse().sendRedirect(authorizeUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信回调登录
|
||||||
|
* @param callback
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@GetMapping("/weChartLogin")
|
||||||
|
public Object weChartLogin(AuthCallback callback, HttpServletRequest request)
|
||||||
|
{
|
||||||
|
return thirdLogin("weChart",getWeChatAuthRequest(),callback);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 钉钉回调
|
* 钉钉回调
|
||||||
*/
|
*/
|
||||||
|
@ -91,16 +93,73 @@ public class ThirdOauthController extends BaseController {
|
||||||
@GetMapping("/dingTalkLogin")
|
@GetMapping("/dingTalkLogin")
|
||||||
public Object callbackAuth(AuthCallback callback, HttpServletRequest request)
|
public Object callbackAuth(AuthCallback callback, HttpServletRequest request)
|
||||||
{
|
{
|
||||||
|
return thirdLogin("dingtalk",getDingTalkAuthRequest(),callback);
|
||||||
|
}
|
||||||
|
|
||||||
String source="dingtalk";
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否授权
|
||||||
|
*/
|
||||||
|
@PostMapping("/checkAuthUser")
|
||||||
|
@ResponseBody
|
||||||
|
public AjaxResult checkAuthUser(SysAuthUser authUser)
|
||||||
|
{
|
||||||
|
Long userId = ShiroUtils.getUserId();
|
||||||
|
String source = authUser.getSource();
|
||||||
|
if (userMapper.checkAuthUser(userId, source) > 0)
|
||||||
|
{
|
||||||
|
return error(source + "平台账号已经绑定");
|
||||||
|
}
|
||||||
|
return AjaxResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消授权
|
||||||
|
*/
|
||||||
|
@PostMapping("/unlock")
|
||||||
|
@ResponseBody
|
||||||
|
public AjaxResult unlockAuth(SysAuthUser authUser)
|
||||||
|
{
|
||||||
|
return toAjax(userMapper.deleteAuthUser(authUser.getAuthId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建钉钉AuthRequest
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private AuthRequest getDingTalkAuthRequest() {
|
||||||
String appId= iSysConfigService.selectConfigByKey("ding.login.appid");
|
String appId= iSysConfigService.selectConfigByKey("ding.login.appid");
|
||||||
String appSecret= iSysConfigService.selectConfigByKey("ding.login.appSecret");
|
String appSecret= iSysConfigService.selectConfigByKey("ding.login.appSecret");
|
||||||
String redirectUri= iSysConfigService.selectConfigByKey("ding.login.redirectUri");
|
String redirectUri= iSysConfigService.selectConfigByKey("ding.login.redirectUri");
|
||||||
AuthRequest authRequest = new AuthDingTalkRequest(AuthConfig.builder()
|
return new AuthDingTalkRequest(AuthConfig.builder()
|
||||||
.clientId(appId)
|
.clientId(appId)
|
||||||
.clientSecret(appSecret)
|
.clientSecret(appSecret)
|
||||||
.redirectUri(redirectUri)
|
.redirectUri(redirectUri)
|
||||||
.build());
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建企业微信AuthRequest
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private AuthRequest getWeChatAuthRequest() {
|
||||||
|
return new AuthWeChatEnterpriseRequest(AuthConfig.builder()
|
||||||
|
.clientId("ww2354bcd694497bd8")
|
||||||
|
.clientSecret("EzODWvC9zdPJJS4KnCNVENB3UhSiYCbmr9UrFpOM9dQ")
|
||||||
|
.redirectUri("http://workflow.vaiwan.com/third/oauth/weChartLogin")
|
||||||
|
.agentId("1000002")
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建登录
|
||||||
|
* @param source 来源
|
||||||
|
* @param authRequest 请求参数
|
||||||
|
* @param callback 请求参数
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Object thirdLogin(String source, AuthRequest authRequest,AuthCallback callback){
|
||||||
AuthResponse<AuthUser> response = authRequest.login(callback);
|
AuthResponse<AuthUser> response = authRequest.login(callback);
|
||||||
if (response.ok())
|
if (response.ok())
|
||||||
{
|
{
|
||||||
|
@ -139,30 +198,4 @@ public class ThirdOauthController extends BaseController {
|
||||||
return new ModelAndView("error/404");
|
return new ModelAndView("error/404");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查是否授权
|
|
||||||
*/
|
|
||||||
@PostMapping("/checkAuthUser")
|
|
||||||
@ResponseBody
|
|
||||||
public AjaxResult checkAuthUser(SysAuthUser authUser)
|
|
||||||
{
|
|
||||||
Long userId = ShiroUtils.getUserId();
|
|
||||||
String source = authUser.getSource();
|
|
||||||
if (userMapper.checkAuthUser(userId, source) > 0)
|
|
||||||
{
|
|
||||||
return error(source + "平台账号已经绑定");
|
|
||||||
}
|
|
||||||
return AjaxResult.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 取消授权
|
|
||||||
*/
|
|
||||||
@PostMapping("/unlock")
|
|
||||||
@ResponseBody
|
|
||||||
public AjaxResult unlockAuth(SysAuthUser authUser)
|
|
||||||
{
|
|
||||||
return toAjax(userMapper.deleteAuthUser(authUser.getAuthId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,15 +167,15 @@ public class SysIndexController extends BaseController
|
||||||
sysNotice.setNoticeType("1");
|
sysNotice.setNoticeType("1");
|
||||||
List<SysNotice> sysNotices = sysNoticeService.selectNoticeList(sysNotice);
|
List<SysNotice> sysNotices = sysNoticeService.selectNoticeList(sysNotice);
|
||||||
mmap.put("sysNotices",sysNotices);
|
mmap.put("sysNotices",sysNotices);
|
||||||
if(CollectionUtil.isNotEmpty(sysNotices)&&sysNotices.size()>4){
|
if(CollectionUtil.isNotEmpty(sysNotices)&&sysNotices.size()>5){
|
||||||
mmap.put("sysNoticeList",sysNotices.subList(0,4));
|
mmap.put("sysNoticeList",sysNotices.subList(0,5));
|
||||||
}else {
|
}else {
|
||||||
mmap.put("sysNoticeList",sysNotices);
|
mmap.put("sysNoticeList",sysNotices);
|
||||||
}
|
}
|
||||||
mmap.put("sysNoticeListSize",sysNotices.size());
|
mmap.put("sysNoticeListSize",sysNotices.size());
|
||||||
HistoricTaskInstanceDTO historicTaskInstanceDTO=new HistoricTaskInstanceDTO();
|
HistoricTaskInstanceDTO historicTaskInstanceDTO=new HistoricTaskInstanceDTO();
|
||||||
historicTaskInstanceDTO.setPageNum(1);
|
historicTaskInstanceDTO.setPageNum(1);
|
||||||
historicTaskInstanceDTO.setPageSize(4);
|
historicTaskInstanceDTO.setPageSize(5);
|
||||||
historicTaskInstanceDTO.setUserId(String.valueOf(sysUser.getUserId()));
|
historicTaskInstanceDTO.setUserId(String.valueOf(sysUser.getUserId()));
|
||||||
PageModel<HistoricTaskInstanceVO> historicTaskInstance = flowableService.getHistoricTaskInstance(historicTaskInstanceDTO);
|
PageModel<HistoricTaskInstanceVO> historicTaskInstance = flowableService.getHistoricTaskInstance(historicTaskInstanceDTO);
|
||||||
mmap.put("historicTaskInstanceList",historicTaskInstance.getPagedRecords());
|
mmap.put("historicTaskInstanceList",historicTaskInstance.getPagedRecords());
|
||||||
|
|
|
@ -71,8 +71,8 @@
|
||||||
<img src="../static/img/dingtalk.png" th:src="@{/img/dingtalk.png}"/>
|
<img src="../static/img/dingtalk.png" th:src="@{/img/dingtalk.png}"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="item" title="功能开发中...">
|
<div class="item" title="使用 企业微信 账号授权登录">
|
||||||
<a href="#">
|
<a th:href="@{/third/oauth/toDingPage/weChart}">
|
||||||
<img src="../static/img/weixin.svg" th:src="@{/img/weixin.svg}"/>
|
<img src="../static/img/weixin.svg" th:src="@{/img/weixin.svg}"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
</h3>
|
</h3>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
<h2 class="m-xs text-center"> <span class="text-warning text-center" style="font-size:1em">待办数 - [[${flowGeneralSituation.todoTaskNum}]]</span></h2>
|
<h2 class="m-xs text-center"> <span class="text-warning text-center" style="font-size:0.8em">待办数 - [[${flowGeneralSituation.todoTaskNum}]]</span></h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
</h3>
|
</h3>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
<h2 class="m-xs text-center"> <span class="text-primary text-center" style="font-size:1em">已办数 - [[${flowGeneralSituation.doneTaskNum}]]</span></h2>
|
<h2 class="m-xs text-center"> <span class="text-primary text-center" style="font-size:0.8em">已办数 - [[${flowGeneralSituation.doneTaskNum}]]</span></h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</h3>
|
</h3>
|
||||||
<br/>
|
<br/>
|
||||||
<h2 class="m-xs text-center">
|
<h2 class="m-xs text-center">
|
||||||
<span class="text-success text-center" style="font-size:1em">流程数 - [[${flowGeneralSituation.myStartProcessInstanceNum}]]</span>
|
<span class="text-success text-center" style="font-size:0.8em">流程数 - [[${flowGeneralSituation.myStartProcessInstanceNum}]]</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -86,7 +86,7 @@
|
||||||
</h3>
|
</h3>
|
||||||
<br/>
|
<br/>
|
||||||
<h2 class="m-xs text-center">
|
<h2 class="m-xs text-center">
|
||||||
<span class="text-danger text-center" style="font-size:1em"> 超时数 - [[${flowGeneralSituation.threeTodoTaskNum}]]</span>
|
<span class="text-danger text-center" style="font-size:0.8em"> 超时数 - [[${flowGeneralSituation.threeTodoTaskNum}]]</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -176,7 +176,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-primary btn-block m-t" th:if="${sysNoticeListSize} gt 2"><i class="fa fa-arrow-down"></i> 加载更多</button>
|
<button class="btn btn-primary btn-block m-t" th:if="${sysNoticeListSize} gt 4">
|
||||||
|
<a onclick="openMoreNotice()">
|
||||||
|
<i class="fa fa-arrow-down"></i> 加载更多
|
||||||
|
</a>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -197,7 +201,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-primary btn-block m-t" th:if="${historicTaskInstanceSize} gt 2"><i class="fa fa-arrow-down"></i> 加载更多</button>
|
<button class="btn btn-primary btn-block m-t" th:if="${historicTaskInstanceSize} gt 4">
|
||||||
|
<a onclick="openMoreHistoricTask()">
|
||||||
|
<i class="fa fa-arrow-down"></i> 加载更多
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -353,6 +362,12 @@
|
||||||
var detailUrl="/system/notice/detail/"+id;
|
var detailUrl="/system/notice/detail/"+id;
|
||||||
$.modal.openTab("公告详情", detailUrl);
|
$.modal.openTab("公告详情", detailUrl);
|
||||||
}
|
}
|
||||||
|
function openMoreNotice(){
|
||||||
|
$.modal.openTab("公告管理","/system/notice");
|
||||||
|
}
|
||||||
|
function openMoreHistoricTask(){
|
||||||
|
$.modal.openTab("我的已办","/flow/toMyTakePartInProcess");
|
||||||
|
}
|
||||||
function hisTaskDetail(detailUrl) {
|
function hisTaskDetail(detailUrl) {
|
||||||
$.modal.openTab("我的已办", detailUrl);
|
$.modal.openTab("我的已办", detailUrl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,7 +151,7 @@
|
||||||
<a class="third-app" href="javascript:void(0)" th:onclick="authUrl('dingtalk');" title="使用 DingTalk 账号授权登录">
|
<a class="third-app" href="javascript:void(0)" th:onclick="authUrl('dingtalk');" title="使用 DingTalk 账号授权登录">
|
||||||
<div class="git-other-login-icon"><img th:src="@{/img/dingding.jpg}"></div>
|
<div class="git-other-login-icon"><img th:src="@{/img/dingding.jpg}"></div>
|
||||||
<span class="app-name">DingTalk</span></a>
|
<span class="app-name">DingTalk</span></a>
|
||||||
<a class="third-app" href="#" title="功能开发中...">
|
<a class="third-app" href="javascript:void(0)" th:onclick="authUrl('weChart');" title="使用 企业微信 账号授权登录">
|
||||||
<div class="git-other-login-icon"><img th:src="@{/img/weixin.svg}"></div>
|
<div class="git-other-login-icon"><img th:src="@{/img/weixin.svg}"></div>
|
||||||
<span class="app-name">WeiXin</span></a>
|
<span class="app-name">WeiXin</span></a>
|
||||||
|
|
||||||
|
|
|
@ -157,6 +157,12 @@
|
||||||
<version>2.6</version>
|
<version>2.6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>weixin-java-cp</artifactId>
|
||||||
|
<version>4.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
Loading…
Reference in New Issue