diff --git a/doc/info.txt b/doc/info.txt
new file mode 100644
index 000000000..362b4d9d6
--- /dev/null
+++ b/doc/info.txt
@@ -0,0 +1,25 @@
+
+我发一下服务器的信息:
+grow.xxzzu.com
+47.92.6.215
+mysql 和 linux 的密码都是
+gywj@1qaz@WSX
+
+数据库使用
+sys_manager
+测试存储过程可以使用 :
+proc_DS01E_enterprise_info
+
+当前,ms_muster 数据库 未更新,等开发模式确定后,一起逐一更新数据结构
+
+小象智租 微信 开发者ID(AppID)
+AppID:wx08196c4219236ab5
+AppSecret:9a131c53016eb64e1f55161326307bbf
+
+appId:wx08196c4219236ab5
+授权回调域:grow.xxzzu.com
+
+
+微信开放平台:(open.weixin.qq.com)
+注册邮箱:jcjytbkt@126.com
+密码:xx-621588+-
diff --git a/doc/xxzzu.conf b/doc/xxzzu.conf
new file mode 100644
index 000000000..105a5eb10
--- /dev/null
+++ b/doc/xxzzu.conf
@@ -0,0 +1,30 @@
+server {
+ listen 80;
+ server_name grow.xxzzu.com;
+
+ location ^~ /system {
+ proxy_pass http://127.0.0.1:8081;
+ }
+
+ location ~ .*\.(js|css)?$ {
+ expires 12h;
+ access_log off;
+ }
+
+ location / {
+ index index.html index index.htm;
+ alias /www/muster-ui;
+ }
+
+ location ^~ /common/ {
+ proxy_pass http://127.0.0.1:8081;
+ }
+
+ #文件资源映射路径
+ location /profile {
+ alias /www/muster/upload;
+ access_log off;
+ log_not_found off;
+ }
+
+}
diff --git a/muster-admin/pom.xml b/muster-admin/pom.xml
index 17c12b148..4eb5b3b68 100644
--- a/muster-admin/pom.xml
+++ b/muster-admin/pom.xml
@@ -73,6 +73,17 @@
muster-generator
+
+
+ com.muster
+ muster-logic
+
+
+
+ com.google.code.gson
+ gson
+
+
diff --git a/muster-admin/src/main/java/com/muster/web/controller/common/CommonController.java b/muster-admin/src/main/java/com/muster/web/controller/common/CommonController.java
index a2bfa89e5..e727e8b5c 100644
--- a/muster-admin/src/main/java/com/muster/web/controller/common/CommonController.java
+++ b/muster-admin/src/main/java/com/muster/web/controller/common/CommonController.java
@@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
-import com.muster.common.config.RuoYiConfig;
+import com.muster.common.config.MusterConfig;
import com.muster.common.constant.Constants;
import com.muster.common.core.domain.AjaxResult;
import com.muster.common.utils.StringUtils;
@@ -46,7 +46,7 @@ public class CommonController
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
}
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
- String filePath = RuoYiConfig.getDownloadPath() + fileName;
+ String filePath = MusterConfig.getDownloadPath() + fileName;
response.setCharacterEncoding("utf-8");
response.setContentType("multipart/form-data");
@@ -73,7 +73,7 @@ public class CommonController
try
{
// 上传文件路径
- String filePath = RuoYiConfig.getUploadPath();
+ String filePath = MusterConfig.getUploadPath();
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
@@ -95,7 +95,7 @@ public class CommonController
public void resourceDownload(String name, HttpServletRequest request, HttpServletResponse response) throws Exception
{
// 本地资源路径
- String localPath = RuoYiConfig.getProfile();
+ String localPath = MusterConfig.getProfile();
// 数据库资源地址
String downloadPath = localPath + StringUtils.substringAfter(name, Constants.RESOURCE_PREFIX);
// 下载名称
diff --git a/muster-admin/src/main/java/com/muster/web/controller/common/WeChatController.java b/muster-admin/src/main/java/com/muster/web/controller/common/WeChatController.java
new file mode 100755
index 000000000..8e8be2a96
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/common/WeChatController.java
@@ -0,0 +1,165 @@
+package com.muster.web.controller.common;
+
+
+import com.muster.common.constant.WxConsts;
+import com.muster.common.core.controller.BaseController;
+import com.muster.common.core.domain.AjaxResult;
+import com.muster.common.utils.StringUtils;
+import com.muster.common.utils.file.MimeTypeUtils;
+import com.muster.common.utils.uuid.IdUtils;
+import com.muster.web.controller.muster.weixin.QrCodeUtils;
+import com.muster.web.controller.muster.weixin.WeChatService;
+import com.muster.web.controller.muster.weixin.WeiXinCommonUtil;
+import com.muster.web.controller.muster.weixin.WeiXinOauth2Token;
+import com.muster.web.controller.muster.weixin.WeiXinUserInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @ClassName WeiXinController
+ * @Description TOOD
+ * @Author guoconglin
+ * @DATE 2020/4/10 14:29
+ * @Version 1.0
+ **/
+
+@RestController
+@Api(value = "微信相关操作管理", description = "微信相关操作管理", tags = {"微信相关操作管理"})
+@RequestMapping("/system/wechat")
+public class WeChatController extends BaseController {
+
+ @Value("${wx.open.appid}")
+ private String wxMapAppid;
+
+ @Value("${wx.open.appsecret}")
+ private String wxMapAppsecret;
+
+ @Value("${wx.open.callback_url}")
+ private String wxMapCallbackUrl;
+
+ @Autowired
+ private WeChatService weChatService;
+
+ @GetMapping("/callback")
+ @ApiOperation("微信回调接口")
+ @ApiImplicitParams(value = {
+ @ApiImplicitParam(name = "redirectUri", value = "跳转url", dataType = "String"),
+ @ApiImplicitParam(name = "code", value = "微信授权的Code", dataType = "String")
+ })
+ public void callback(HttpServletResponse response, HttpServletRequest request,
+ @RequestParam("redirectUri") String redirectUri,
+ @RequestParam(value = "code", required = false) String code,
+ @RequestParam("state") String state) throws IOException {
+ String redirectUrl = String.format("%s?code=%s&state=%s", redirectUri , code, state);
+ response.sendRedirect(redirectUrl);
+ }
+
+ /**
+ * <1>用户访问微信网页版,此时微信服务器会为其生成一个全局唯一的UUID。然后这个UUID就 回调路径wxMapCallbackUrl的后面,
+ * 此时该操作并没有和用户有交互,所以该ID仅仅是个唯一字符串而已,系统并不知道该ID会和哪个用户相绑定。
+ 如果此时你不断地刷新,你会发现每次的ID都会发生过变化。感兴趣的可以自己手动来抓包,这里就不做示范了。
+ 注意:此时服务器和你网页还会建立一个长连接(websocket),为了节约系统资源,如果一段时间不扫描,便会超时。返回状态为408。
+
+ <2>用户扫描PC端的二维码,然后用户和服务创建一个长链接(websocket)判断当前状态,并且。这个步骤的目的是为了获取起生成的全局唯一UUID,进行前端状态变化。
+
+ <3>用户如果此时授权,则会像系统发送一条请求,并且将UUID和code一块发送过去,然后根据code获取微信用户信息,看系统是否存在该用户,不存在,则将微信用户信息保存,然后让用户取绑定账号
+ <4> 如果用户输入的账号也不存在,则需要用户开通账号(开通账号方式分为自己注册和要求管理员开通),
+ 4.1 如果自己注册,则开始走注册流程,走注册流程的话,审核流程通过之后,然后重新扫码绑定。
+ 4.2 如果需要管理员开通账号,开通账号之后,首次扫码登录或者微信授权登录都需要重新绑定一次
+
+ <5>系统受到这一步的目的是将UUIIDI和用户账号(或token)绑定在一起,因为二者都是唯一,便可以确定唯一的对应关系。
+ 处理完该关系后,系统会向PC端反馈消息,这个UUID对应的用户是A,然后网页便可请求加载A的微信信息和资料
+
+ */
+
+ @GetMapping("/wxQrMapCode")
+ @ApiOperation("获取微信公众号二维码")
+ @ApiImplicitParams(value = {
+ @ApiImplicitParam(name = "width",value = "图片宽度",dataType = "Integer"),
+ @ApiImplicitParam(name = "height",value = "图片高度",dataType = "Integer")
+ })
+ public AjaxResult wxQrMapCode(@RequestParam(value = "width", required = false, defaultValue = "100") int width,
+ @RequestParam(value = "height", required = false, defaultValue = "100") int height) {
+ AjaxResult ajax = AjaxResult.success();
+ // 唯一标识
+ String uuid = IdUtils.simpleUUID();
+// //将uuid带到回调地址上,判断当前用户是否使用了
+ String authorizeUrl = WeiXinCommonUtil.getAuthorizeUrl(wxMapAppid, String.format(wxMapCallbackUrl,uuid), WxConsts.QrConnectScope.SNSAPI_LOGIN, null);
+ String qrCodeBasePicture = QrCodeUtils.getQrCodeBasePicture(authorizeUrl, width, height, MimeTypeUtils.getExtension(MimeTypeUtils.IMAGE_PNG));
+ ajax.put("img", qrCodeBasePicture);
+ ajax.put("uuid",uuid);
+ return ajax;
+ }
+
+ @PostMapping("/user-info")
+ @ApiOperation("通过authorizeCode获取微信用户信息,并进行判断,让前端根据返回的参数去判断")
+ @ApiImplicitParam(name = "authorizeCode",value = "微信授权authorizeCode",dataType = "String")
+ public AjaxResult getWeChatCode(@RequestParam("authorizeCode") String authorizeCode,
+ @RequestParam("state") String state,
+ @RequestParam("appId") String appId,
+ @RequestParam("bizId") String bizId){
+ if(StringUtils.isNotNull(authorizeCode)){
+ WeiXinOauth2Token oauth2AccessToken = WeiXinCommonUtil.getOauth2AccessToken(authorizeCode, wxMapAppid, wxMapAppsecret);
+ if(StringUtils.isNotNull(oauth2AccessToken)){
+ if(oauth2AccessToken.getErrcode()==0){
+// String refreshToken = oauth2AccessToken.getRefreshToken();
+ String accessToken = oauth2AccessToken.getAccessToken();
+ String openId = oauth2AccessToken.getOpenId();
+// //校验授权token是否有效,false则取刷新token
+// boolean b = WeiXinCommonUtil.validateToken(refreshToken, wxMapAppid);
+// if(!b){
+// refreshToken = WeiXinCommonUtil.getRefreshToken(wxMapAppid, refreshToken);
+// }
+
+ WeiXinUserInfo userInfo = WeiXinCommonUtil.getUserInfo(accessToken, openId);
+ boolean loginFlag = weChatService.login(userInfo, appId, bizId);
+ if (loginFlag) {
+
+ return AjaxResult.success(userInfo);
+ }
+
+
+ //先拿openId去库里查找微信信息标
+// BWxOpenUser bWxOpenUser = ibWxOpenUserService.selectByOpenId(openId);
+// // 如果没有则获取微信用户信息,插入数据库
+// if(StringUtils.isNull(bWxOpenUser)){
+// //获取微信用户信息
+// WeiXinUserInfo userInfo = WeiXinCommonUtil.getUserInfo(refreshToken, openId);
+// if(StringUtils.isNotNull(userInfo) && userInfo.getErrcode()==0){
+// ibWxOpenUserService.saveWxOpenUser(userInfo);
+// }
+// }else {
+// return AjaxResult.success(openId);
+// }
+ //如果有则判断userId有没有,如果userId为0或者null,则返回让用户绑定账号。如果有,则使用userId查询sys_user标,将user_name和password查找到,使用loginService登录判断
+
+ }
+
+ }
+ return AjaxResult.error("登录异常,请重试");
+
+ }else {
+ return AjaxResult.error("参数不合法,请传入授权码");
+ }
+ }
+
+ @GetMapping("/pushToWeb/{uuid}")
+ public AjaxResult pushToWeb(@PathVariable String uuid){
+ //TODO 写逻辑
+ return AjaxResult.success();
+ }
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/WeiXinController.java b/muster-admin/src/main/java/com/muster/web/controller/muster/WeiXinController.java
new file mode 100755
index 000000000..097cd8ee2
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/WeiXinController.java
@@ -0,0 +1,66 @@
+package com.muster.web.controller.muster;
+
+
+import com.muster.common.constant.Constants;
+import com.muster.common.constant.WxConsts;
+import com.muster.common.core.domain.AjaxResult;
+import com.muster.framework.web.service.SysLoginService;
+import com.muster.web.controller.muster.weixin.WeChatService;
+import com.muster.web.controller.muster.weixin.WeiXinUserInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * @ClassName WeiXinController
+ * @Description TOOD
+ * @Author guoconglin
+ * @DATE 2020/4/10 14:29
+ * @Version 1.0
+ **/
+@Controller
+@Api(value = "微信相关操作管理", description = "微信相关操作管理", tags = {"微信相关操作管理"})
+@RequestMapping("/system/weixin")
+public class WeiXinController {
+
+ @Autowired
+ private WeChatService weChatService;
+
+ @Autowired
+ private SysLoginService loginService;
+
+ private String prefix = "weixin";
+
+ @GetMapping("/redirect")
+ public String user()
+ {
+ return prefix + "/redirect";
+ }
+
+ @PostMapping("/login")
+ @ResponseBody
+ @ApiOperation("子系统通过微信登录")
+ @ApiImplicitParam(name = "子系统通过微信登录",value = "子系统通过微信登录", dataTypeClass = WeiXinUserInfo.class)
+ public AjaxResult login(@RequestBody WeiXinUserInfo weiXinUserInfo) {
+
+ boolean loginFlag = weChatService.login(weiXinUserInfo);
+
+ if (loginFlag) {
+ AjaxResult ajax = AjaxResult.success();
+ String token = loginService.login(WxConsts.Account.SHRIO_USERNAME, WxConsts.Account.SHRIO_PASSWORD);
+
+ ajax.put(Constants.TOKEN, token);
+ return ajax;
+
+ }
+ return AjaxResult.error("微信扫码登录失败,请重试");
+ }
+
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/JsApiTicket.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/JsApiTicket.java
new file mode 100755
index 000000000..ce9c04fb9
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/JsApiTicket.java
@@ -0,0 +1,34 @@
+package com.muster.web.controller.muster.weixin;
+
+
+/**
+ * @ClassName JsApiTicket
+ * @Description TOOD 获取授权页ticket 获取的ticket和有效期
+ * @Author guoconglin
+ * @DATE 2020/4/10 10:39
+ * @Version 1.0
+ **/
+
+public class JsApiTicket {
+
+ // 接口访问凭证
+ private String ticket;
+ // 凭证有效期,单位:秒
+ private int expiresIn;
+
+ public String getTicket() {
+ return ticket;
+ }
+
+ public void setTicket(String ticket) {
+ this.ticket = ticket;
+ }
+
+ public int getExpiresIn() {
+ return expiresIn;
+ }
+
+ public void setExpiresIn(int expiresIn) {
+ this.expiresIn = expiresIn;
+ }
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/MyX509TrustManager.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/MyX509TrustManager.java
new file mode 100755
index 000000000..a30d0c8ba
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/MyX509TrustManager.java
@@ -0,0 +1,31 @@
+package com.muster.web.controller.muster.weixin;
+
+import javax.net.ssl.X509TrustManager;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+/**
+ * @ClassName MyX509TrustManager
+ * @Description TOOD
+ * @Author guoconglin
+ * @DATE 2020/4/10 10:47
+ * @Version 1.0
+ **/
+
+
+public class MyX509TrustManager implements X509TrustManager {
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/QrCodeUtils.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/QrCodeUtils.java
new file mode 100755
index 000000000..42094c15c
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/QrCodeUtils.java
@@ -0,0 +1,46 @@
+package com.muster.web.controller.muster.weixin;
+
+
+import cn.hutool.extra.qrcode.QrCodeUtil;
+import com.muster.common.utils.sign.Base64;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * @ClassName QrCodeUtils
+ * @Description TOOD 生成二维码图片
+ * @Author guoconglin
+ * @DATE 2020/4/10 13:57
+ * @Version 1.0
+ **/
+
+
+public class QrCodeUtils {
+
+ /**
+ * 生成二维码方法返回到流
+ * @author guoconglin
+ * @date 2020/4/10 13:44
+ * @param: [url 访问链接, width 图片宽, height 图片高, mimeType 类型比图png\jpg, resp]
+ * @return: void
+ */
+ public static void getQrcode(String url,int width,int height,String mimeType, HttpServletResponse resp) throws Exception {
+ QrCodeUtil.generate(url,width,height, mimeType,resp.getOutputStream());
+ }
+
+ /**
+ * 生成base64图片
+ * @author guoconglin
+ * @date 2020/4/10 13:49
+ * @param: [url 访问链接, width 图片宽, height 图片高, mimeType 类型比图png\jpg]
+ * @return: java.lang.String
+ */
+ public static String getQrCodeBasePicture(String url,int width,int height,String mimeType){
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ QrCodeUtil.generate(url,width,height,mimeType,stream);
+ String base64EnCode = Base64.encode(stream.toByteArray());
+ return base64EnCode;
+ }
+
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/SignUtil.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/SignUtil.java
new file mode 100755
index 000000000..c3cc89782
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/SignUtil.java
@@ -0,0 +1,79 @@
+package com.muster.web.controller.muster.weixin;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * @ClassName SignUtil
+ * @Description TOOD 微信签名
+ * @Author guoconglin
+ * @DATE 2020/4/10 13:17
+ * @Version 1.0
+ **/
+
+
+public class SignUtil {
+
+ public static Map sign(String jsapi_ticket, String url) {
+ Map ret = new HashMap();
+ String nonce_str = create_nonce_str();
+ String timestamp = create_timestamp();
+ String string1;
+ String signature = "";
+
+ //注意这里参数名必须全部小写,且必须有序
+ string1 = "jsapi_ticket=" + jsapi_ticket +
+ "&noncestr=" + nonce_str +
+ "×tamp=" + 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);
+ }
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/Token.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/Token.java
new file mode 100755
index 000000000..3289ee472
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/Token.java
@@ -0,0 +1,34 @@
+package com.muster.web.controller.muster.weixin;
+
+
+/**
+ * @ClassName Token
+ * @Description TOOD 获取的token 和有效时间
+ * @Author guoconglin
+ * @DATE 2020/4/10 10:40
+ * @Version 1.0
+ **/
+
+public class Token {
+
+ // 接口访问凭证
+ private String accessToken;
+ // 凭证有效期,单位:秒
+ private int expiresIn;
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+
+ public int getExpiresIn() {
+ return expiresIn;
+ }
+
+ public void setExpiresIn(int expiresIn) {
+ this.expiresIn = expiresIn;
+ }
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/URIUtil.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/URIUtil.java
new file mode 100755
index 000000000..c4681d795
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/URIUtil.java
@@ -0,0 +1,58 @@
+package com.muster.web.controller.muster.weixin;
+
+import com.muster.common.utils.StringUtils;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * @ClassName URIUtil
+ * @Description TOOD 网站转码
+ * @Author guoconglin
+ * @DATE 2020/4/10 12:50
+ * @Version 1.0
+ **/
+
+
+public class URIUtil {
+
+ private static final String ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()";
+
+ public static String encodeURIComponent(String input) {
+ if (StringUtils.isEmpty(input)) {
+ return input;
+ }
+
+ int l = input.length();
+ StringBuilder o = new StringBuilder(l * 3);
+ try {
+ for (int i = 0; i < l; i++) {
+ String e = input.substring(i, i + 1);
+ if (ALLOWED_CHARS.indexOf(e) == -1) {
+ byte[] b = e.getBytes("utf-8");
+ o.append(getHex(b));
+ continue;
+ }
+ o.append(e);
+ }
+ return o.toString();
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ return input;
+ }
+
+ private static String getHex(byte buf[]) {
+ StringBuilder o = new StringBuilder(buf.length * 3);
+ for (int i = 0; i < buf.length; i++) {
+ int n = buf[i] & 0xff;
+ o.append("%");
+ if (n < 0x10) {
+ o.append("0");
+ }
+ o.append(Long.toString(n, 16).toUpperCase());
+ }
+ return o.toString();
+ }
+}
+
+
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeChatService.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeChatService.java
new file mode 100644
index 000000000..b575ed594
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeChatService.java
@@ -0,0 +1,19 @@
+package com.muster.web.controller.muster.weixin;
+
+/**
+ * Description
+ *
+ *
+ * DATE 2020-07-08.
+ *
+ * @author 刘江涛.
+ */
+public interface WeChatService {
+
+ int query(final String openId);
+
+ boolean login(final WeiXinUserInfo userInfo);
+
+ boolean login(final WeiXinUserInfo userInfo, String appId, String bizId);
+
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeChatServiceImpl.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeChatServiceImpl.java
new file mode 100644
index 000000000..94f07e1ec
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeChatServiceImpl.java
@@ -0,0 +1,75 @@
+package com.muster.web.controller.muster.weixin;
+
+import com.muster.common.config.MusterConfig;
+import com.muster.common.constant.WxConsts;
+import com.muster.logic.DbLogicService;
+import com.muster.logic.model.ProcedureResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Description
+ *
+ *
+ * DATE 2020-07-11.
+ *
+ * @author 刘江涛.
+ */
+@Component
+public class WeChatServiceImpl implements WeChatService{
+
+ private DbLogicService storedProcedure;
+
+ /** 微信用户 */
+ public final static String PROC_DU02A_USER_LOGIN = "proc_DU02A_user_login";
+ public final static String PROC_DU02C_USER_CREATE = "proc_DU02C_user_create";
+ @Autowired
+ WeChatServiceImpl (DbLogicService storedProcedure) {
+ this.storedProcedure = storedProcedure;
+ }
+
+ @Override
+ public int query(final String openId) {
+ return 1;
+ }
+
+
+ @Override
+ public boolean login(final WeiXinUserInfo userInfo) {
+ return this.login(userInfo, MusterConfig.getAppId(), MusterConfig.getBizId());
+ }
+
+ @Override
+ public boolean login(final WeiXinUserInfo userInfo, String appId, String bizId) {
+ // 创建账号
+ Map params = new HashMap<>();
+ params.put("01_acc_type", WxConsts.Account.TYPE);
+ params.put("02_username", userInfo.getWxOpenid());
+ params.put("03_password", WxConsts.Account.PASSWORD);
+ params.put("04_userip", "0.0.0.0");
+ params.put("appId", appId);
+ params.put("bizId", bizId);
+
+ int createRes = this.create(params);
+ if (createRes > 0) {
+ int loginRes = this.login(params);
+ return loginRes > 0;
+ }
+ return false;
+ }
+
+ private int create( final Map params) {
+ Map p = new HashMap<>(params);
+ p.put("05_json", "{}");
+ ProcedureResult createRes = storedProcedure.exec(PROC_DU02C_USER_CREATE, p);
+ return createRes.getRes();
+ }
+
+ private int login(final Map params) {
+ ProcedureResult loginRes = storedProcedure.exec(PROC_DU02A_USER_LOGIN, params);
+ return loginRes.getRes();
+ }
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WechatQRCode.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WechatQRCode.java
new file mode 100755
index 000000000..28e8cdbb9
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WechatQRCode.java
@@ -0,0 +1,44 @@
+package com.muster.web.controller.muster.weixin;
+
+
+/**
+ * @ClassName WechatQRCode
+ * @Description TOOD 二维码参数
+ * @Author guoconglin
+ * @DATE 2020/4/10 13:29
+ * @Version 1.0
+ **/
+
+public class WechatQRCode {
+
+ // 获取的二维码
+ private String ticket;
+ // 二维码的有效时间,单位为秒,最大不超过2592000(即30天)
+ private int expire_seconds;
+ // 二维码图片解析后的地址
+ private String url;
+
+ public String getTicket() {
+ return ticket;
+ }
+
+ public void setTicket(String ticket) {
+ this.ticket = ticket;
+ }
+
+ public int getExpire_seconds() {
+ return expire_seconds;
+ }
+
+ public void setExpire_seconds(int expire_seconds) {
+ this.expire_seconds = expire_seconds;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeiXinCommonUtil.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeiXinCommonUtil.java
new file mode 100755
index 000000000..03ec32c4a
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeiXinCommonUtil.java
@@ -0,0 +1,641 @@
+package com.muster.web.controller.muster.weixin;
+
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+import com.muster.common.utils.StringUtils;
+import com.muster.common.utils.http.HttpUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.ConnectException;
+import java.net.URL;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @ClassName WeiXinCommonUtil
+ * @Description TOOD 微信通用工具类
+ * @Author guoconglin
+ * @DATE 2020/4/10 10:38
+ * @Version 1.0
+ **/
+
+
+public class WeiXinCommonUtil {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WeiXinCommonUtil.class);
+
+
+ private static Map weixinCache = new HashMap();
+
+ private static Map tokenCache = new HashMap();
+
+ // 临时二维码
+ private static final String QR_SCENE = "QR_SCENE";
+ // 永久二维码
+ private static final String QR_LIMIT_SCENE = "QR_LIMIT_SCENE";
+ // 永久二维码(字符串)
+ private static final String QR_LIMIT_STR_SCENE = "QR_LIMIT_STR_SCENE";
+ // 创建二维码
+ private static final String create_ticket_path = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=%s";
+ // 通过ticket换取二维码
+ private static final String showqrcode_path = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s";
+
+ // 凭证获取(GET)
+ public static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
+ /**
+ * 长链接转短链接接口
+ */
+ public static final String SHORTURL_API_URL = "https://api.weixin.qq.com/cgi-bin/shorturl?access_token=%s";
+ /**
+ * 获取access_token
+ */
+ public static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
+
+ /**
+ * 获得jsapi_ticket
+ */
+ public static final String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
+
+ /**
+ * 通过access token获得jsapi_ticket
+ */
+ public static final String TOKEN_GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi";
+
+ /**
+ * 用code换取oauth2的access token
+ */
+ public static final String OAUTH2_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
+ /**
+ * 刷新oauth2的access token
+ */
+ public static final String OAUTH2_REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s";
+ /**
+ * 用oauth2获取用户信息
+ */
+ public static final String OAUTH2_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s";
+ /**
+ * 验证oauth2的access token是否有效
+ */
+ public static final String OAUTH2_VALIDATE_TOKEN_URL = "https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s";
+ /**
+ * 获取微信服务器IP地址
+ */
+ public static final String GET_CALLBACK_IP_URL = "https://api.weixin.qq.com/cgi-bin/getcallbackip";
+ /**
+ * 第三方使用网站应用授权登录的url
+ */
+ public static final String QRCONNECT_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect";
+ /**
+ * oauth2授权的url连接
+ */
+ public static final String CONNECT_OAUTH2_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect";
+
+ /**
+ * 获取公众号的自动回复规则
+ */
+ public static final String GET_CURRENT_AUTOREPLY_INFO_URL = "https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info";
+
+ /**
+ * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零
+ */
+ public static final String CLEAR_QUOTA_URL = "https://api.weixin.qq.com/cgi-bin/clear_quota";
+
+ /**
+ * 通过openId 获取公众号用户详细信息
+ */
+ public static final String OAUTH2_USERINFO_URLS = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=%s";
+
+ /**
+ * 公众号发送模板消息链接
+ */
+ public static final String SEND_MP_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s";
+
+
+
+
+ /**
+ * 获取接口访问凭证
+ * @author guoconglin
+ * @date 2020/4/10 10:44
+ * @param: [appId 微信平台开账号的appId, appSecret 微信开放平台开账号后的appSecret]
+ * @return: com.sanqi.common.utils.weixin.Token
+ */
+ public static Token getToken(String appId,String appSecret) {
+ Token token = null;
+ String requestUrl = String.format(TOKEN_URL,appId,appSecret);
+ // 发起GET请求获取凭证
+ JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);
+ LOG.info("获取token jsonObject jsonObject:{}", jsonObject);
+ if (null != jsonObject) {
+ try {
+ token = new Token();
+ token.setAccessToken(jsonObject.getString("access_token"));
+ token.setExpiresIn(jsonObject.getIntValue("expires_in"));
+ } catch (JSONException e) {
+ token = null;
+ // 获取token失败
+ LOG.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getIntValue("errcode"), jsonObject.getString("errmsg"));
+ }
+ }
+ return token;
+ }
+
+ /**
+ * 刷新token
+ * @param appId 微信平台开的唯一标识
+ * @param accessToken token
+ * @return
+ */
+ public static String getRefreshToken(String appId,String accessToken){
+ String refreshToken = String.format(OAUTH2_REFRESH_TOKEN_URL,appId,accessToken);
+ return refreshToken;
+ }
+
+ /**
+ * 验证token是否有效
+ * @param refreshToken 刷新获取到的新token
+ * @param appId 微信平台开的唯一标识
+ * @return
+ */
+ public static boolean validateToken(String refreshToken,String appId){
+ String refreshTokenUrl = String.format(OAUTH2_VALIDATE_TOKEN_URL,refreshToken,appId);
+ JSONObject jsonObject = httpsRequest(refreshTokenUrl, "GET", null);
+ if(jsonObject != null){
+ //TODO需要判断
+ int errcode = jsonObject.getIntValue("errcode");
+ if(errcode == 0){ //则证明有效
+ return true;
+ }else {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 获取微信授权页面链接
+ * @param appId 微信平台开的唯一标识
+ * @param redirectURI 回调地址
+ * @param scope
+ * @param state
+ * @return
+ */
+ public static String getAuthorizeUrl(String appId,String redirectURI, String scope, String state){
+ String authorizeUrl = String.format(QRCONNECT_URL,appId,URIUtil.encodeURIComponent(redirectURI),scope, StringUtils.trimToEmpty(state));
+ return authorizeUrl;
+ }
+
+ /**
+ * 用code换取oauth2的access token
+ * @author guoconglin
+ * @date 2020/4/10 12:55
+ * @param: [code, appId 微信平台唯一识别appId, appSecret 微信平台唯一识别appSecret]
+ * @return: com.sanqi.common.utils.weixin.WeiXinOauth2Token
+ */
+ public static WeiXinOauth2Token getOauth2AccessToken(String code,String appId,String appSecret){
+ WeiXinOauth2Token weixinOauth2Token = new WeiXinOauth2Token();
+ String getTokenUrl = String.format(OAUTH2_ACCESS_TOKEN_URL, appId, appSecret, code);
+ JSONObject jsonObject = httpsRequest(getTokenUrl, "GET", null);
+ LOG.info("获取网页授权凭证 jsonObject:{}",jsonObject);
+ if (null != jsonObject) {
+ if(jsonObject.getIntValue("errcode") == 0){
+ weixinOauth2Token.setAccessToken(jsonObject.getString("access_token"));
+ weixinOauth2Token.setExpiresIn(jsonObject.getIntValue("expires_in"));
+ weixinOauth2Token.setRefreshToken(jsonObject.getString("refresh_token"));
+ weixinOauth2Token.setOpenId(jsonObject.getString("openid"));
+ weixinOauth2Token.setScope(jsonObject.getString("scope"));
+ weixinOauth2Token.setErrcode(jsonObject.getIntValue("errcode"));
+ weixinOauth2Token.setErrmsg(jsonObject.getString("errmsg"));
+ weixinOauth2Token.setUnionId(jsonObject.containsKey("unionid")?jsonObject.getString("unionid"):null);
+ LOG.info("获取网页授权凭证成功 weixinOauth2Token:{}",weixinOauth2Token);
+ }else {
+ int errorCode = jsonObject.getIntValue("errcode");
+ String errorMsg = jsonObject.getString("errmsg");
+ weixinOauth2Token.setErrcode(errorCode);
+ weixinOauth2Token.setErrmsg(errorMsg);
+ LOG.error("获取网页授权凭证失败 errcode:{} errmsg:{}", errorCode, errorMsg);
+ }
+ }
+ return weixinOauth2Token;
+ }
+
+
+ /**
+ * 通过网页授权获取用户信息
+ * @author guoconglin
+ * @date 2020/4/10 13:00
+ * @param: [accessToken 获取的token, openId 用户的openId]
+ * @return: com.sanqi.common.utils.weixin.WeiXinUserInfo
+ */
+ public static WeiXinUserInfo getUserInfo(String accessToken, String openId){
+ WeiXinUserInfo weixinUserInfo = new WeiXinUserInfo();
+ String userInfoUrl = String.format(OAUTH2_USERINFO_URL, accessToken, openId, "zh_CN");
+ JSONObject jsonObject = httpsRequest(userInfoUrl, "GET", null);
+ LOG.info("jsonObject:{}",jsonObject);
+ LOG.info("jsonObject:{}",jsonObject.getIntValue("subscribe"));
+ if (null != jsonObject) {
+ try {
+ if(jsonObject.getIntValue("errcode") == 0){
+ // 用户的标识
+ if(jsonObject.containsKey("openid")){
+ weixinUserInfo.setWxOpenid(jsonObject.getString("openid"));
+ }
+ if(jsonObject.containsKey("subscribe")){
+ // 关注状态(1是关注,0是未关注),未关注时获取不到其余信息
+ int subscribe = jsonObject.getIntValue("subscribe");
+ weixinUserInfo.setSubscribe(subscribe);
+ }
+ // 用户关注时间
+ if(jsonObject.containsKey("subscribe_time")){
+ weixinUserInfo.setSubscribeTime(jsonObject.getString("subscribe_time"));
+ }
+ // 昵称
+ if(jsonObject.containsKey("nickname")){
+ weixinUserInfo.setNickName(jsonObject.getString("nickname"));
+ }
+ // 用户的性别(1是男性,2是女性,0是未知)
+ if(jsonObject.containsKey("sex")){
+ weixinUserInfo.setSex(jsonObject.getIntValue("sex"));
+ }
+ // 用户所在国家
+ if(jsonObject.containsKey("country")){
+ weixinUserInfo.setCountry(jsonObject.getString("country"));
+ }
+ // 用户所在省份
+ if(jsonObject.containsKey("province")){
+ weixinUserInfo.setProvince(jsonObject.getString("province"));
+ }
+ // 用户所在城市
+ if(jsonObject.containsKey("city")){
+ weixinUserInfo.setCity(jsonObject.getString("city"));
+ }
+ // 用户的语言,简体中文为zh_CN
+ if(jsonObject.containsKey("language")){
+ weixinUserInfo.setLanguage(jsonObject.getString("language"));
+ }
+ // 用户头像
+ if(jsonObject.containsKey("headimgurl")){
+ weixinUserInfo.setHeadImgUrl(jsonObject.getString("headimgurl"));
+ }
+ //unionid
+ if(jsonObject.containsKey("unionid")){
+ weixinUserInfo.setUnionId(jsonObject.getString("unionid"));
+ }
+ int errorCode = jsonObject.getIntValue("errcode");
+ String errorMsg = jsonObject.getString("errmsg");
+ weixinUserInfo.setErrcode(errorCode);
+ weixinUserInfo.setErrmsg(errorMsg);
+ LOG.info("获取用户信息成功 weixinUserInfo:{}", weixinUserInfo);
+ }
+
+ } catch (Exception e) {
+ int errorCode = jsonObject.getIntValue("errcode");
+ String errorMsg = jsonObject.getString("errmsg");
+ weixinUserInfo.setErrcode(errorCode);
+ weixinUserInfo.setErrmsg(errorMsg);
+ LOG.error("获取用户信息失败 errcode:{} errmsg:{}", errorCode, errorMsg);
+ }
+ }
+ return weixinUserInfo;
+ }
+
+ /**
+ * 创建调用jsapi时所需要的签名
+ * @author guoconglin
+ * @date 2020/4/10 13:19
+ * @param: [url, mpAppId, mpSecret]
+ * @return: com.sanqi.common.utils.weixin.WxJsapiSignature
+ */
+ public static WxJsapiSignature createJsapiSignature(String url,String mpAppId,String mpSecret) throws ParseException {
+ LOG.info("创建调用jsapi时所需要的签名 url:{} ",url);
+ String token_str = null;
+ Token token = tokenCache.get("accessToken");
+ if(StringUtils.isNotNull(token)){
+ int expiresIn = token.getExpiresIn();
+ Calendar ever = Calendar.getInstance();
+ Date date = new Date(expiresIn*1000L);
+ ever.setTime(date);
+ Calendar current = Calendar.getInstance();
+ if(ever.after(current)){
+ token_str = token.getAccessToken();
+ LOG.info("获取的accessToken:{}",token_str);
+ }else {
+ token_str = getWxJsapiTokenStr(mpAppId, mpSecret);
+ }
+ }else{
+ token_str = getWxJsapiTokenStr(mpAppId, mpSecret);
+ }
+ WxJsapiSignature wxJsapiSignature = null;
+ String ticket_str = null;
+ LOG.info("weixinCache:{}",weixinCache);
+ JsApiTicket jsApiTicket = weixinCache.get("ticket");
+ LOG.info("获取jsApiTicket成功 jsApiTicket:{}", jsApiTicket);
+ if(jsApiTicket != null){
+ int expiresIn = jsApiTicket.getExpiresIn();
+ Calendar ever = Calendar.getInstance();
+ Date date = new Date(expiresIn*1000L);
+ ever.setTime(date);
+ Calendar current = Calendar.getInstance();
+ if(ever.after(current)) {
+ ticket_str = jsApiTicket.getTicket();
+ LOG.info("获取jsApiTicket成功 ticket_str:{}", ticket_str);
+ }else{
+ String ticketUrl = String.format(TOKEN_GET_JSAPI_TICKET_URL,token_str);
+ JSONObject jsonObject = httpsRequest(ticketUrl, "GET", null);
+ if(jsonObject != null){
+ try {
+ ticket_str = jsonObject.getString("ticket");
+ JsApiTicket jsApiTicket1 = new JsApiTicket();
+ weixinCache.remove("ticket");
+ jsApiTicket1.setTicket(jsonObject.getString("ticket"));
+ LOG.info("获取jticket的值为: ticket:{}",jsonObject.getString("ticket"));
+ jsApiTicket1.setExpiresIn(jsonObject.getIntValue("expires_in"));
+ weixinCache.put("ticket", jsApiTicket1);
+ } catch (JSONException e) {
+ token = null;
+ // 获取jsApiTicket失败
+ LOG.error("获取jsApiTicket失败 errcode:{} errmsg:{}", jsonObject.getIntValue("errcode"), jsonObject.getString("errmsg"));
+ }
+ }
+ }
+ Map sign = SignUtil.sign(ticket_str, url);
+ wxJsapiSignature = new WxJsapiSignature();
+ wxJsapiSignature.setAppId(mpAppId);
+ wxJsapiSignature.setNonceStr(sign.get("nonceStr"));
+ wxJsapiSignature.setTimestamp(Long.parseLong(sign.get("timestamp")));
+ wxJsapiSignature.setSignature(sign.get("signature"));
+ LOG.info("获取jsApiTicket成功 wxJsapiSignature:{}", wxJsapiSignature);
+ }else{
+ String ticketUrl = String.format(TOKEN_GET_JSAPI_TICKET_URL,token_str);
+ JSONObject jsonObject = httpsRequest(ticketUrl, "GET", null);
+ LOG.info("jsonObject 请求jsonObject:{}",jsonObject);
+ if(jsonObject != null){
+ try {
+ JsApiTicket jsApiTicket1 = new JsApiTicket();
+ weixinCache.remove("ticket");
+ jsApiTicket1.setTicket(jsonObject.getString("ticket"));
+ jsApiTicket1.setExpiresIn(jsonObject.getIntValue("expires_in"));
+ weixinCache.put("ticket", jsApiTicket1);
+ LOG.info("获取ticket成功 ========= ticket:{}", jsApiTicket1);
+ Map sign = SignUtil.sign(jsApiTicket1.getTicket(), url);
+ wxJsapiSignature = new WxJsapiSignature();
+ wxJsapiSignature.setAppId(mpAppId);
+ wxJsapiSignature.setNonceStr(sign.get("nonceStr"));
+ wxJsapiSignature.setTimestamp(Long.parseLong(sign.get("timestamp")));
+ wxJsapiSignature.setSignature(sign.get("signature"));
+ LOG.info("获取jsApiTicket成功 ========= wxJsapiSignature:{}", wxJsapiSignature);
+ } catch (JSONException e) {
+ token = null;
+ // 获取jsApiTicket失败
+ LOG.error("获取jsApiTicket失败 errcode:{} errmsg:{}", jsonObject.getIntValue("errcode"), jsonObject.getString("errmsg"));
+ }
+ }
+ }
+ return wxJsapiSignature;
+ }
+
+ private static String getWxJsapiTokenStr(String mpAppId,String mpSecret){
+ String token_str = null;
+ Token token = getToken(mpAppId, mpSecret);
+ LOG.info("获取的token1:{}",token);
+ if(StringUtils.isNotNull(token)){
+ token_str = token.getAccessToken();
+ tokenCache.remove("accessToken");
+ tokenCache.put("accessToken",token);
+ }else{
+ LOG.info("失败{} {}");
+ }
+ LOG.info("获取的第二次accessToken:{}",token_str);
+ return token_str;
+ }
+
+ /**
+ * 创建临时带参数二维码
+ * @param accessToken
+ * @expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
+ * @param sceneId 场景Id
+ * @return
+ */
+ public static String createTempTicket(String accessToken, String expireSeconds, int sceneId) {
+ WechatQRCode wxQRCode = null;
+ Map intMap = new HashMap();
+ intMap.put("scene_id",sceneId);
+ Map> mapMap = new HashMap>();
+ mapMap.put("scene", intMap);
+ //
+ Map paramsMap = new HashMap();
+ paramsMap.put("expire_seconds", expireSeconds);
+ paramsMap.put("action_name", QR_SCENE);
+ paramsMap.put("action_info", mapMap);
+ String data = new Gson().toJson(paramsMap);
+ System.out.println("创建临时带参数二维码参数"+data);
+ String requestUrl = String.format(create_ticket_path,accessToken);
+ data = HttpUtils.sendPost( requestUrl, data);
+ System.out.println("创建临时带参数二维码返回结果"+data);
+ try {
+ wxQRCode = new Gson().fromJson(data, WechatQRCode.class);
+ } catch (JsonSyntaxException e) {
+ wxQRCode = null;
+ e.printStackTrace();
+ }
+ System.out.println("创建临时带参数二维码返回转换对象"+wxQRCode);
+ return wxQRCode==null?null:wxQRCode.getUrl();
+
+ }
+
+ /**
+ * 创建永久二维码(数字)
+ * @param accessToken
+ * @param sceneId 场景Id
+ * @return
+ */
+ public static String createForeverTicket(String accessToken, int sceneId) {
+
+ //output data
+ Map intMap = new HashMap();
+ intMap.put("scene_id",sceneId);
+ Map> mapMap = new HashMap>();
+ mapMap.put("scene", intMap);
+ //
+ Map paramsMap = new HashMap();
+ paramsMap.put("action_name", QR_LIMIT_SCENE);
+ paramsMap.put("action_info", mapMap);
+ String data = new Gson().toJson(paramsMap);
+ System.out.println("创建临时带参数二维码参数"+data);
+ String requestUrl = String.format(create_ticket_path,accessToken);
+ data = HttpUtils.sendPost( requestUrl, data);
+ System.out.println("创建临时带参数二维码返回结果"+data);
+ WechatQRCode wxQRCode = null;
+ try {
+ wxQRCode = new Gson().fromJson(data, WechatQRCode.class);
+ } catch (JsonSyntaxException e) {
+ wxQRCode = null;
+ e.printStackTrace();
+ }
+ return wxQRCode==null?null:wxQRCode.getTicket();
+ }
+
+ /**
+ * 创建永久二维码(字符串)
+ *
+ * @param accessToken
+ * @param sceneStr 场景str
+ * @return
+ */
+ public static String createForeverStrTicket(String accessToken, String sceneStr){
+ //output data
+ Map intMap = new HashMap();
+ intMap.put("scene_str",sceneStr);
+ Map> mapMap = new HashMap>();
+ mapMap.put("scene", intMap);
+
+ Map paramsMap = new HashMap();
+ paramsMap.put("action_name", QR_LIMIT_STR_SCENE);
+ paramsMap.put("action_info", mapMap);
+ String data = new Gson().toJson(paramsMap);
+ System.out.println("创建临时带参数二维码参数"+data);
+ String requestUrl = String.format(create_ticket_path,accessToken);
+ data = HttpUtils.sendPost( requestUrl, data);
+ System.out.println("创建临时带参数二维码返回结果"+data);
+ WechatQRCode wxQRCode = null;
+ try {
+ wxQRCode = new Gson().fromJson(data, WechatQRCode.class);
+ } catch (JsonSyntaxException e) {
+ wxQRCode = null;
+ }
+ return wxQRCode==null?null:wxQRCode.getTicket();
+ }
+
+
+ /**
+ * 获取二维码ticket后,通过ticket换取二维码图片展示
+ * @param ticket
+ * @return
+ */
+ public static String showQrcode(String ticket){
+ System.out.println("通过ticket换取二维码图片展示参数==="+ticket);
+ String s = null;
+ try {
+ s = HttpUtils.sendGet(String.format(showqrcode_path,urlEncodeUTF8(ticket)),"");
+ System.out.println("通过ticket换取二维码图片展示参数==="+s);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return s;
+ }
+
+ /**
+ * URL编码(utf-8)
+ *
+ * @param source
+ * @return
+ */
+ public static String urlEncodeUTF8(String source) {
+ String result = source;
+ try {
+ result = java.net.URLEncoder.encode(source, "utf-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ /**
+ * 长链接生成短链接
+ * @param longUrl 长链接地址
+ * @param accessToken token令牌
+ * @return
+ */
+ public static String Long2Short(String longUrl,String accessToken){
+ Map paramsMap = new HashMap();
+ paramsMap.put("action", "long2short");
+ paramsMap.put("long_url", longUrl);
+ String data = new Gson().toJson(paramsMap);
+ String requestUrl = String.format(SHORTURL_API_URL,accessToken);
+ data = HttpUtils.sendPost(requestUrl,data);
+ JSONObject jsonObject = JSONObject.parseObject(data);
+ return jsonObject.getString("short_url");
+ }
+
+
+
+
+
+
+
+ /**
+ * 发送https请求
+ *
+ * @param requestUrl 请求地址
+ * @param requestMethod 请求方式(GET、POST)
+ * @param outputStr 提交的数据
+ * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
+ */
+ public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
+ JSONObject jsonObject = null;
+ try {
+ // 创建SSLContext对象,并使用我们指定的信任管理器初始化
+ TrustManager[] tm = { new MyX509TrustManager() };
+ SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
+ sslContext.init(null, tm, new java.security.SecureRandom());
+ // 从上述SSLContext对象中得到SSLSocketFactory对象
+ SSLSocketFactory ssf = sslContext.getSocketFactory();
+
+ URL url = new URL(requestUrl);
+ HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
+ conn.setSSLSocketFactory(ssf);
+
+ conn.setDoOutput(true);
+ conn.setDoInput(true);
+ conn.setUseCaches(false);
+ // 设置请求方式(GET/POST)
+ conn.setRequestMethod(requestMethod);
+
+ // 当outputStr不为null时向输出流写数据
+ if (null != outputStr) {
+ OutputStream outputStream = conn.getOutputStream();
+ // 注意编码格式
+ outputStream.write(outputStr.getBytes("UTF-8"));
+ outputStream.close();
+ }
+
+ // 从输入流读取返回内容
+ InputStream inputStream = conn.getInputStream();
+ InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
+ BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
+ String str = null;
+ StringBuffer buffer = new StringBuffer();
+ while ((str = bufferedReader.readLine()) != null) {
+ buffer.append(str);
+ }
+
+ // 释放资源
+ bufferedReader.close();
+ inputStreamReader.close();
+ inputStream.close();
+ conn.disconnect();
+ jsonObject = JSONObject.parseObject(buffer.toString());
+ } catch (ConnectException ce) {
+ LOG.error("连接超时:{}", ce);
+ } catch (Exception e) {
+ LOG.error("https请求异常:{}", e);
+ }
+ return jsonObject;
+ }
+
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeiXinOauth2Token.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeiXinOauth2Token.java
new file mode 100755
index 000000000..5427123da
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeiXinOauth2Token.java
@@ -0,0 +1,96 @@
+package com.muster.web.controller.muster.weixin;
+
+
+/**
+ * @ClassName WeiXinOauth2Token
+ * @Description TOOD 微信授权
+ * @Author guoconglin
+ * @DATE 2020/4/10 10:13
+ * @Version 1.0
+ **/
+
+public class WeiXinOauth2Token {
+
+ // 网页授权接口调用凭证
+ private String accessToken;
+ // 凭证有效时长
+ private int expiresIn;
+ // 用于刷新凭证
+ private String refreshToken;
+ // 用户标识
+ private String openId;
+ // 用户授权作用域
+ private String scope;
+
+ //unionId
+ private String unionId;
+
+ //错误码
+ private int errcode;
+ //错误信息
+ private String errmsg;
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+
+ public int getExpiresIn() {
+ return expiresIn;
+ }
+
+ public void setExpiresIn(int expiresIn) {
+ this.expiresIn = expiresIn;
+ }
+
+ public String getRefreshToken() {
+ return refreshToken;
+ }
+
+ public void setRefreshToken(String refreshToken) {
+ this.refreshToken = refreshToken;
+ }
+
+ public String getOpenId() {
+ return openId;
+ }
+
+ public void setOpenId(String openId) {
+ this.openId = openId;
+ }
+
+ public String getScope() {
+ return scope;
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+
+ public String getUnionId() {
+ return unionId;
+ }
+
+ public void setUnionId(String unionId) {
+ this.unionId = unionId;
+ }
+
+ public int getErrcode() {
+ return errcode;
+ }
+
+ public void setErrcode(int errcode) {
+ this.errcode = errcode;
+ }
+
+ public String getErrmsg() {
+ return errmsg;
+ }
+
+ public void setErrmsg(String errmsg) {
+ this.errmsg = errmsg;
+ }
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeiXinUserInfo.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeiXinUserInfo.java
new file mode 100755
index 000000000..33b081007
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WeiXinUserInfo.java
@@ -0,0 +1,166 @@
+package com.muster.web.controller.muster.weixin;
+
+
+/**
+ * @ClassName WeiXinUserInfo
+ * @Description TOOD
+ * @Author guoconglin
+ * @DATE 2020/4/10 12:59
+ * @Version 1.0
+ **/
+
+public class WeiXinUserInfo {
+
+ // 用户的标识
+ private String wxOpenid;
+ // 关注状态(1是关注,0是未关注),未关注时获取不到其余信息
+ private int subscribe;
+ // 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
+ private String subscribeTime;
+ // 昵称
+ private String nickName;
+ // 用户的性别(1是男性,2是女性,0是未知)
+ private int sex;
+ // 用户所在国家
+ private String country;
+ // 用户所在省份
+ private String province;
+ // 用户所在城市
+ private String city;
+ // 用户的语言,简体中文为zh_CN
+ private String language;
+ // 用户头像
+ private String headImgUrl;
+
+ //用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的
+ private String unionId;
+
+ //错误码
+ private int errcode;
+ //错误信息
+ private String errmsg;
+
+ public String getWxOpenid() {
+ return wxOpenid;
+ }
+
+ public void setWxOpenid(String wxOpenid) {
+ this.wxOpenid = wxOpenid;
+ }
+
+ public int getSubscribe() {
+ return subscribe;
+ }
+
+ public void setSubscribe(int subscribe) {
+ this.subscribe = subscribe;
+ }
+
+ public String getSubscribeTime() {
+ return subscribeTime;
+ }
+
+ public void setSubscribeTime(String subscribeTime) {
+ this.subscribeTime = subscribeTime;
+ }
+
+ public String getNickName() {
+ return nickName;
+ }
+
+ public void setNickName(String nickName) {
+ this.nickName = nickName;
+ }
+
+ public int getSex() {
+ return sex;
+ }
+
+ public void setSex(int sex) {
+ this.sex = sex;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public String getProvince() {
+ return province;
+ }
+
+ public void setProvince(String province) {
+ this.province = province;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public String getHeadImgUrl() {
+ return headImgUrl;
+ }
+
+ public void setHeadImgUrl(String headImgUrl) {
+ this.headImgUrl = headImgUrl;
+ }
+
+ public String getUnionId() {
+ return unionId;
+ }
+
+ public void setUnionId(String unionId) {
+ this.unionId = unionId;
+ }
+
+ public int getErrcode() {
+ return errcode;
+ }
+
+ public void setErrcode(int errcode) {
+ this.errcode = errcode;
+ }
+
+ public String getErrmsg() {
+ return errmsg;
+ }
+
+ public void setErrmsg(String errmsg) {
+ this.errmsg = errmsg;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("WeiXinUserInfo{");
+ sb.append("wxOpenid='").append(wxOpenid).append('\'');
+ sb.append(", subscribe=").append(subscribe);
+ sb.append(", subscribeTime='").append(subscribeTime).append('\'');
+ sb.append(", nickName='").append(nickName).append('\'');
+ sb.append(", sex=").append(sex);
+ sb.append(", country='").append(country).append('\'');
+ sb.append(", province='").append(province).append('\'');
+ sb.append(", city='").append(city).append('\'');
+ sb.append(", language='").append(language).append('\'');
+ sb.append(", headImgUrl='").append(headImgUrl).append('\'');
+ sb.append(", unionId='").append(unionId).append('\'');
+ sb.append(", errcode=").append(errcode);
+ sb.append(", errmsg='").append(errmsg).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WxJsapiSignature.java b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WxJsapiSignature.java
new file mode 100755
index 000000000..0937f77b8
--- /dev/null
+++ b/muster-admin/src/main/java/com/muster/web/controller/muster/weixin/WxJsapiSignature.java
@@ -0,0 +1,86 @@
+package com.muster.web.controller.muster.weixin;
+
+
+import java.io.Serializable;
+
+/**
+ * @ClassName WxJsapiSignature
+ * @Description TOOD
+ * @Author guoconglin
+ * @DATE 2020/4/10 13:14
+ * @Version 1.0
+ **/
+
+public class WxJsapiSignature implements Serializable {
+
+ private static final long serialVersionUID = -1116808193154384804L;
+
+ /**
+ * 公众号的唯一标识
+ */
+ private String appId;
+
+ /**
+ * 生成签名的随机串
+ */
+ private String nonceStr;
+
+ /**
+ * 生成签名的时间戳
+ */
+ private long timestamp;
+
+ /**
+ * 地址
+ */
+ private String url;
+
+ /**
+ * 签名
+ */
+ private String signature;
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public String getNonceStr() {
+ return nonceStr;
+ }
+
+ public void setNonceStr(String nonceStr) {
+ this.nonceStr = nonceStr;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getSignature() {
+ return signature;
+ }
+
+ public void setSignature(String signature) {
+ this.signature = signature;
+ }
+}
diff --git a/muster-admin/src/main/java/com/muster/web/controller/system/SysProfileController.java b/muster-admin/src/main/java/com/muster/web/controller/system/SysProfileController.java
index d6e96a5b0..bef794a6a 100644
--- a/muster-admin/src/main/java/com/muster/web/controller/system/SysProfileController.java
+++ b/muster-admin/src/main/java/com/muster/web/controller/system/SysProfileController.java
@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.muster.common.annotation.Log;
-import com.muster.common.config.RuoYiConfig;
+import com.muster.common.config.MusterConfig;
import com.muster.common.core.controller.BaseController;
import com.muster.common.core.domain.AjaxResult;
import com.muster.common.core.domain.entity.SysUser;
@@ -111,7 +111,7 @@ public class SysProfileController extends BaseController
if (!file.isEmpty())
{
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
- String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file);
+ String avatar = FileUploadUtils.upload(MusterConfig.getAvatarPath(), file);
if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
{
AjaxResult ajax = AjaxResult.success();
diff --git a/muster-admin/src/main/java/com/muster/web/core/config/SwaggerConfig.java b/muster-admin/src/main/java/com/muster/web/core/config/SwaggerConfig.java
index 0ab3599f1..d5a734196 100644
--- a/muster-admin/src/main/java/com/muster/web/core/config/SwaggerConfig.java
+++ b/muster-admin/src/main/java/com/muster/web/core/config/SwaggerConfig.java
@@ -6,7 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import com.muster.common.config.RuoYiConfig;
+import com.muster.common.config.MusterConfig;
import io.swagger.annotations.ApiOperation;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
@@ -32,7 +32,7 @@ public class SwaggerConfig
{
/** 系统基础配置 */
@Autowired
- private RuoYiConfig ruoyiConfig;
+ private MusterConfig ruoyiConfig;
/** 是否开启swagger */
@Value("${swagger.enabled}")
diff --git a/muster-admin/src/main/resources/application-dev.yml b/muster-admin/src/main/resources/application-dev.yml
new file mode 100644
index 000000000..195a6a1a3
--- /dev/null
+++ b/muster-admin/src/main/resources/application-dev.yml
@@ -0,0 +1,11 @@
+muster:
+ # 文件路径 示例( Windows配置D:/muster/uploadPath,Linux配置 /home/muster/uploadPath)
+ profile: /Users/liujiangtao/project/mishang/muster-vue
+
+# 开发环境配置
+server:
+ # 服务器的HTTP端口,默认为8080
+ port: 8080
+ servlet:
+ # 应用的访问路径
+ context-path: /
\ No newline at end of file
diff --git a/muster-admin/src/main/resources/application-prod.yml b/muster-admin/src/main/resources/application-prod.yml
new file mode 100644
index 000000000..92bdd86e1
--- /dev/null
+++ b/muster-admin/src/main/resources/application-prod.yml
@@ -0,0 +1,12 @@
+muster:
+ # 文件路径 示例( Windows配置D:/muster/uploadPath,Linux配置 /home/muster/uploadPath)
+ profile: /www/muster/upload
+
+
+# 开发环境配置
+server:
+ # 服务器的HTTP端口,默认为8080
+ port: 8081
+ servlet:
+ # 应用的访问路径
+ context-path: /prod-api
diff --git a/muster-admin/src/main/resources/application.yml b/muster-admin/src/main/resources/application.yml
index 92a6157a1..ddf8cfcea 100644
--- a/muster-admin/src/main/resources/application.yml
+++ b/muster-admin/src/main/resources/application.yml
@@ -5,11 +5,9 @@ muster:
# 版本
version: 3.0.0
# 版权年份
- copyrightYear: 2019
+ copyrightYear: 2020
# 实例演示开关
demoEnabled: true
- # 文件路径 示例( Windows配置D:/muster/uploadPath,Linux配置 /home/muster/uploadPath)
- profile: /Users/liujiangtao/project/mishang/muster-vue
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数组计算 char 字符验证
@@ -17,11 +15,6 @@ muster:
# 开发环境配置
server:
- # 服务器的HTTP端口,默认为8080
- port: 8080
- servlet:
- # 应用的访问路径
- context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
@@ -107,7 +100,7 @@ swagger:
# 是否开启swagger
enabled: true
# 请求前缀
- pathMapping: /dev-api
+ pathMapping: /prod-api
# 防止XSS攻击
xss:
@@ -117,3 +110,14 @@ xss:
excludes: /system/notice/*
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
+
+#微信
+wx:
+ #微信开放平台
+ open:
+ #开放平台appid
+ appid: wx08196c4219236ab5
+ #开放平台appsecret
+ appsecret: 9a131c53016eb64e1f55161326307bbf
+ #回调地址
+ callback_url: http://grow.xxzzu.com/system/wechat/callback
diff --git a/muster-common/pom.xml b/muster-common/pom.xml
index e933c59f1..1a420fcc5 100644
--- a/muster-common/pom.xml
+++ b/muster-common/pom.xml
@@ -119,6 +119,12 @@
javax.servlet-api
+
+
+ cn.hutool
+ hutool-all
+
+
\ No newline at end of file
diff --git a/muster-common/src/main/java/com/muster/common/config/RuoYiConfig.java b/muster-common/src/main/java/com/muster/common/config/MusterConfig.java
similarity index 68%
rename from muster-common/src/main/java/com/muster/common/config/RuoYiConfig.java
rename to muster-common/src/main/java/com/muster/common/config/MusterConfig.java
index 4e6107747..28ab6d442 100644
--- a/muster-common/src/main/java/com/muster/common/config/RuoYiConfig.java
+++ b/muster-common/src/main/java/com/muster/common/config/MusterConfig.java
@@ -10,7 +10,7 @@ import org.springframework.stereotype.Component;
*/
@Component
@ConfigurationProperties(prefix = "muster")
-public class RuoYiConfig
+public class MusterConfig
{
/** 项目名称 */
private String name;
@@ -30,6 +30,10 @@ public class RuoYiConfig
/** 获取地址开关 */
private static boolean addressEnabled;
+ private static String appId;
+
+ private static String bizId;
+
public String getName()
{
return name;
@@ -77,7 +81,7 @@ public class RuoYiConfig
public void setProfile(String profile)
{
- RuoYiConfig.profile = profile;
+ MusterConfig.profile = profile;
}
public static boolean isAddressEnabled()
@@ -87,7 +91,7 @@ public class RuoYiConfig
public void setAddressEnabled(boolean addressEnabled)
{
- RuoYiConfig.addressEnabled = addressEnabled;
+ MusterConfig.addressEnabled = addressEnabled;
}
/**
@@ -113,4 +117,40 @@ public class RuoYiConfig
{
return getProfile() + "/upload";
}
+
+ /**
+ * Gets appId.
+ *
+ * @return the appId
+ */
+ public static String getAppId() {
+ return appId;
+ }
+
+ /**
+ * Sets appId.
+ *
+ * @param appId the appId
+ */
+ public void setAppId(final String appId) {
+ MusterConfig.appId = appId;
+ }
+
+ /**
+ * Gets bizId.
+ *
+ * @return the bizId
+ */
+ public static String getBizId() {
+ return bizId;
+ }
+
+ /**
+ * Sets bizId.
+ *
+ * @param bizId the bizId
+ */
+ public void setBizId(final String bizId) {
+ MusterConfig.bizId = bizId;
+ }
}
diff --git a/muster-common/src/main/java/com/muster/common/constant/WxConsts.java b/muster-common/src/main/java/com/muster/common/constant/WxConsts.java
new file mode 100755
index 000000000..dbf2af2c4
--- /dev/null
+++ b/muster-common/src/main/java/com/muster/common/constant/WxConsts.java
@@ -0,0 +1,270 @@
+package com.muster.common.constant;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @ClassName WxConsts
+ * @Description TOOD 微信开发所使用到的常量类.
+ * @Author guoconglin
+ * @DATE 2020/4/10 14:01
+ * @Version 1.0
+ **/
+
+
+public class WxConsts {
+
+ /**
+ * 微信推送过来的消息的类型,和发送给微信xml格式消息的消息类型.
+ */
+ public static class XmlMsgType {
+ public static final String TEXT = "text";
+ public static final String IMAGE = "image";
+ public static final String VOICE = "voice";
+ public static final String SHORTVIDEO = "shortvideo";
+ public static final String VIDEO = "video";
+ public static final String NEWS = "news";
+ public static final String MUSIC = "music";
+ public static final String LOCATION = "location";
+ public static final String LINK = "link";
+ public static final String EVENT = "event";
+ public static final String DEVICE_TEXT = "device_text";
+ public static final String DEVICE_EVENT = "device_event";
+ public static final String DEVICE_STATUS = "device_status";
+ public static final String HARDWARE = "hardware";
+ public static final String TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service";
+ }
+
+ /**
+ * 主动发送消息(即客服消息)的消息类型.
+ */
+ public static class KefuMsgType {
+ /**
+ * 文本消息.
+ */
+ public static final String TEXT = "text";
+ /**
+ * 图片消息.
+ */
+ public static final String IMAGE = "image";
+ /**
+ * 语音消息.
+ */
+ public static final String VOICE = "voice";
+
+ /**
+ * 图文链接.
+ */
+ public static final String LINK = "link";
+ /**
+ /**
+ * 视频消息.
+ */
+ public static final String VIDEO = "video";
+ /**
+ * 音乐消息.
+ */
+ public static final String MUSIC = "music";
+ /**
+ * 图文消息(点击跳转到外链).
+ */
+ public static final String NEWS = "news";
+ /**
+ * 图文消息(点击跳转到图文消息页面).
+ */
+ public static final String MPNEWS = "mpnews";
+ /**
+ * 发送文件(CP专用).
+ */
+ public static final String FILE = "file";
+ /**
+ * 文本卡片消息(CP专用).
+ */
+ public static final String TEXTCARD = "textcard";
+ /**
+ * 卡券消息.
+ */
+ public static final String WXCARD = "wxcard";
+ /**
+ * 转发到客服的消息.
+ */
+ public static final String TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service";
+ }
+
+ /**
+ * 表示是否是保密消息,0表示否,1表示是,默认0.
+ */
+ public static class KefuMsgSafe {
+ public static final String NO = "0";
+ public static final String YES = "1";
+ }
+
+ public static class Account {
+ public static final int TYPE = 2;
+ public static final String PASSWORD = "123456";
+
+ public static final String SHRIO_USERNAME = "admin";
+ public static final String SHRIO_PASSWORD = "admin123";
+
+ }
+
+ /**
+ * 群发消息的消息类型.
+ */
+ public static class MassMsgType {
+ public static final String MPNEWS = "mpnews";
+ public static final String TEXT = "text";
+ public static final String VOICE = "voice";
+ public static final String IMAGE = "image";
+ public static final String MPVIDEO = "mpvideo";
+ }
+
+ /**
+ * 群发消息后微信端推送给服务器的反馈消息.
+ */
+ public static class MassMsgStatus {
+ public static final String SEND_SUCCESS = "send success";
+ public static final String SEND_FAIL = "send fail";
+ public static final String ERR_10001 = "err(10001)";
+ public static final String ERR_20001 = "err(20001)";
+ public static final String ERR_20004 = "err(20004)";
+ public static final String ERR_20002 = "err(20002)";
+ public static final String ERR_20006 = "err(20006)";
+ public static final String ERR_20008 = "err(20008)";
+ public static final String ERR_20013 = "err(20013)";
+ public static final String ERR_22000 = "err(22000)";
+ public static final String ERR_21000 = "err(21000)";
+
+ /**
+ * 群发反馈消息代码所对应的文字描述.
+ */
+ public static final Map STATUS_DESC = new HashMap<>();
+
+ static {
+ STATUS_DESC.put(SEND_SUCCESS, "发送成功");
+ STATUS_DESC.put(SEND_FAIL, "发送失败");
+ STATUS_DESC.put(ERR_10001, "涉嫌广告");
+ STATUS_DESC.put(ERR_20001, "涉嫌政治");
+ STATUS_DESC.put(ERR_20004, "涉嫌社会");
+ STATUS_DESC.put(ERR_20002, "涉嫌色情");
+ STATUS_DESC.put(ERR_20006, "涉嫌违法犯罪");
+ STATUS_DESC.put(ERR_20008, "涉嫌欺诈");
+ STATUS_DESC.put(ERR_20013, "涉嫌版权");
+ STATUS_DESC.put(ERR_22000, "涉嫌互推_互相宣传");
+ STATUS_DESC.put(ERR_21000, "涉嫌其他");
+ }
+ }
+
+ /**
+ * 微信端推送过来的事件类型.
+ */
+ public static class EventType {
+ public static final String SUBSCRIBE = "subscribe";
+ public static final String UNSUBSCRIBE = "unsubscribe";
+ public static final String SCAN = "SCAN";
+ public static final String LOCATION = "LOCATION";
+ public static final String CLICK = "CLICK";
+ public static final String VIEW = "VIEW";
+ public static final String MASS_SEND_JOB_FINISH = "MASSSENDJOBFINISH";
+ public static final String SCANCODE_PUSH = "scancode_push";
+ public static final String SCANCODE_WAITMSG = "scancode_waitmsg";
+ public static final String PIC_SYSPHOTO = "pic_sysphoto";
+ public static final String PIC_PHOTO_OR_ALBUM = "pic_photo_or_album";
+ public static final String PIC_WEIXIN = "pic_weixin";
+ public static final String LOCATION_SELECT = "location_select";
+ public static final String TEMPLATE_SEND_JOB_FINISH = "TEMPLATESENDJOBFINISH";
+ public static final String ENTER_AGENT = "enter_agent";
+ }
+
+ /**
+ * 上传多媒体(临时素材)文件的类型.
+ */
+ public static class MediaFileType {
+ public static final String IMAGE = "image";
+ public static final String VOICE = "voice";
+ public static final String VIDEO = "video";
+ public static final String THUMB = "thumb";
+ public static final String FILE = "file";
+ }
+
+ /**
+ * 自定义菜单的按钮类型.
+ */
+ public static class MenuButtonType {
+ /**
+ * 点击推事件.
+ */
+ public static final String CLICK = "click";
+ /**
+ * 跳转URL.
+ */
+ public static final String VIEW = "view";
+ /**
+ * 跳转到小程序.
+ */
+ public static final String MINIPROGRAM = "miniprogram";
+ /**
+ * 扫码推事件.
+ */
+ public static final String SCANCODE_PUSH = "scancode_push";
+ /**
+ * 扫码推事件且弹出“消息接收中”提示框.
+ */
+ public static final String SCANCODE_WAITMSG = "scancode_waitmsg";
+ /**
+ * 弹出系统拍照发图.
+ */
+ public static final String PIC_SYSPHOTO = "pic_sysphoto";
+ /**
+ * 弹出拍照或者相册发图.
+ */
+ public static final String PIC_PHOTO_OR_ALBUM = "pic_photo_or_album";
+ /**
+ * 弹出微信相册发图器.
+ */
+ public static final String PIC_WEIXIN = "pic_weixin";
+ /**
+ * 弹出地理位置选择器.
+ */
+ public static final String LOCATION_SELECT = "location_select";
+ /**
+ * 下发消息(除文本消息).
+ */
+ public static final String MEDIA_ID = "media_id";
+ /**
+ * 跳转图文消息URL.
+ */
+ public static final String VIEW_LIMITED = "view_limited";
+ }
+
+ /**
+ * oauth2网页授权的scope.
+ */
+ public static class OAuth2Scope {
+ /**
+ * 不弹出授权页面,直接跳转,只能获取用户openid.
+ */
+ public static final String SNSAPI_BASE = "snsapi_base";
+ /**
+ * 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息.
+ */
+ public static final String SNSAPI_USERINFO = "snsapi_userinfo";
+ }
+
+ /**
+ * 网页应用登录授权作用域.
+ */
+ public static class QrConnectScope {
+ public static final String SNSAPI_LOGIN = "snsapi_login";
+ }
+
+ /**
+ * 永久素材类型.
+ */
+ public static class MaterialType {
+ public static final String NEWS = "news";
+ public static final String VOICE = "voice";
+ public static final String IMAGE = "image";
+ public static final String VIDEO = "video";
+ }
+}
diff --git a/muster-common/src/main/java/com/muster/common/utils/file/FileUploadUtils.java b/muster-common/src/main/java/com/muster/common/utils/file/FileUploadUtils.java
index 107de7b3e..5841a1436 100644
--- a/muster-common/src/main/java/com/muster/common/utils/file/FileUploadUtils.java
+++ b/muster-common/src/main/java/com/muster/common/utils/file/FileUploadUtils.java
@@ -4,7 +4,7 @@ import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;
-import com.muster.common.config.RuoYiConfig;
+import com.muster.common.config.MusterConfig;
import com.muster.common.constant.Constants;
import com.muster.common.exception.file.FileNameLengthLimitExceededException;
import com.muster.common.exception.file.FileSizeLimitExceededException;
@@ -33,7 +33,7 @@ public class FileUploadUtils
/**
* 默认上传的地址
*/
- private static String defaultBaseDir = RuoYiConfig.getProfile();
+ private static String defaultBaseDir = MusterConfig.getProfile();
public static void setDefaultBaseDir(String defaultBaseDir)
{
@@ -144,7 +144,7 @@ public class FileUploadUtils
private static final String getPathFileName(String uploadDir, String fileName) throws IOException
{
- int dirLastIndex = RuoYiConfig.getProfile().length() + 1;
+ int dirLastIndex = MusterConfig.getProfile().length() + 1;
String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
return pathFileName;
diff --git a/muster-common/src/main/java/com/muster/common/utils/ip/AddressUtils.java b/muster-common/src/main/java/com/muster/common/utils/ip/AddressUtils.java
index 436942b38..a00fff458 100644
--- a/muster-common/src/main/java/com/muster/common/utils/ip/AddressUtils.java
+++ b/muster-common/src/main/java/com/muster/common/utils/ip/AddressUtils.java
@@ -3,7 +3,7 @@ package com.muster.common.utils.ip;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
-import com.muster.common.config.RuoYiConfig;
+import com.muster.common.config.MusterConfig;
import com.muster.common.constant.Constants;
import com.muster.common.utils.StringUtils;
import com.muster.common.utils.http.HttpUtils;
@@ -31,7 +31,7 @@ public class AddressUtils
{
return "内网IP";
}
- if (RuoYiConfig.isAddressEnabled())
+ if (MusterConfig.isAddressEnabled())
{
try
{
diff --git a/muster-common/src/main/java/com/muster/common/utils/poi/ExcelUtil.java b/muster-common/src/main/java/com/muster/common/utils/poi/ExcelUtil.java
index beb2d6815..aff7b6244 100644
--- a/muster-common/src/main/java/com/muster/common/utils/poi/ExcelUtil.java
+++ b/muster-common/src/main/java/com/muster/common/utils/poi/ExcelUtil.java
@@ -46,7 +46,7 @@ import com.muster.common.annotation.Excel;
import com.muster.common.annotation.Excel.ColumnType;
import com.muster.common.annotation.Excel.Type;
import com.muster.common.annotation.Excels;
-import com.muster.common.config.RuoYiConfig;
+import com.muster.common.config.MusterConfig;
import com.muster.common.core.domain.AjaxResult;
import com.muster.common.core.text.Convert;
import com.muster.common.exception.CustomException;
@@ -739,7 +739,7 @@ public class ExcelUtil
*/
public String getAbsoluteFile(String filename)
{
- String downloadPath = RuoYiConfig.getDownloadPath() + filename;
+ String downloadPath = MusterConfig.getDownloadPath() + filename;
File desc = new File(downloadPath);
if (!desc.getParentFile().exists())
{
diff --git a/muster-framework/src/main/java/com/muster/framework/config/ResourcesConfig.java b/muster-framework/src/main/java/com/muster/framework/config/ResourcesConfig.java
index 5242a42e0..677a92fd5 100644
--- a/muster-framework/src/main/java/com/muster/framework/config/ResourcesConfig.java
+++ b/muster-framework/src/main/java/com/muster/framework/config/ResourcesConfig.java
@@ -9,7 +9,7 @@ import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-import com.muster.common.config.RuoYiConfig;
+import com.muster.common.config.MusterConfig;
import com.muster.common.constant.Constants;
import com.muster.framework.interceptor.RepeatSubmitInterceptor;
@@ -28,7 +28,7 @@ public class ResourcesConfig implements WebMvcConfigurer
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
/** 本地文件上传路径 */
- registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
+ registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + MusterConfig.getProfile() + "/");
/** swagger配置 */
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
diff --git a/muster-framework/src/main/java/com/muster/framework/web/service/SysLoginService.java b/muster-framework/src/main/java/com/muster/framework/web/service/SysLoginService.java
index f4045282e..9533bf2ed 100644
--- a/muster-framework/src/main/java/com/muster/framework/web/service/SysLoginService.java
+++ b/muster-framework/src/main/java/com/muster/framework/web/service/SysLoginService.java
@@ -1,12 +1,5 @@
package com.muster.framework.web.service;
-import javax.annotation.Resource;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.stereotype.Component;
import com.muster.common.constant.Constants;
import com.muster.common.core.domain.model.LoginUser;
import com.muster.common.core.redis.RedisCache;
@@ -17,6 +10,14 @@ import com.muster.common.exception.user.UserPasswordNotMatchException;
import com.muster.common.utils.MessageUtils;
import com.muster.framework.manager.AsyncManager;
import com.muster.framework.manager.factory.AsyncFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
/**
* 登录校验方法
@@ -59,13 +60,26 @@ public class SysLoginService
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
throw new CaptchaException();
}
+ return this.login(username, password);
+ }
+
+ /**
+ * 内部登录验证
+ *
+ * @param username 用户名
+ * @param password 密码
+ * @return 结果
+ */
+ public String login(String username, String password)
+ {
+
// 用户验证
Authentication authentication = null;
try
{
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager
- .authenticate(new UsernamePasswordAuthenticationToken(username, password));
+ .authenticate(new UsernamePasswordAuthenticationToken(username, password));
}
catch (Exception e)
{
diff --git a/muster-generator/src/main/java/com/muster/generator/util/GenUtils.java b/muster-generator/src/main/java/com/muster/generator/util/GenUtils.java
index 92ff0ed56..55d94a283 100644
--- a/muster-generator/src/main/java/com/muster/generator/util/GenUtils.java
+++ b/muster-generator/src/main/java/com/muster/generator/util/GenUtils.java
@@ -200,7 +200,7 @@ public class GenUtils
*/
public static String replaceText(String text)
{
- return RegExUtils.replaceAll(text, "(?:表|若依)", "");
+ return RegExUtils.replaceAll(text, "(?:表|muster)", "");
}
/**
diff --git a/muster-logic/pom.xml b/muster-logic/pom.xml
new file mode 100644
index 000000000..22063bb9f
--- /dev/null
+++ b/muster-logic/pom.xml
@@ -0,0 +1,23 @@
+
+
+
+ muster
+ com.muster
+ 3.0.0
+
+ 4.0.0
+
+ muster-logic
+ 3.0.0
+
+
+
+
+ com.muster
+ muster-framework
+
+
+
+
\ No newline at end of file
diff --git a/muster-logic/src/main/java/com/muster/logic/BO/DaoContext.java b/muster-logic/src/main/java/com/muster/logic/BO/DaoContext.java
new file mode 100644
index 000000000..f0cd679a4
--- /dev/null
+++ b/muster-logic/src/main/java/com/muster/logic/BO/DaoContext.java
@@ -0,0 +1,150 @@
+package com.muster.logic.BO;
+
+/**
+ * Description
+ *
+ *
+ * DATE 2020-07-04.
+ *
+ * @author 刘江涛.
+ */
+public class DaoContext {
+
+ public DaoContext() {
+ }
+
+ public DaoContext(final String appId, final String bizId, final String uhId, final int userId, final int token) {
+ this.appId = appId;
+ this.bizId = bizId;
+ this.uhId = uhId;
+ this.userId = userId;
+ this.token = token;
+ }
+
+ /**
+ * 系统级设定appid
+ */
+ private String appId = "10001";
+
+ /**
+ * 系统级设定bizid 原则上 fx_bizid>0 时,将无权注册企业
+ */
+ private String bizId = "0";
+
+ /**
+ * 用户操作的终端硬件参数
+ */
+ private String uhId = "test";
+
+ /**
+ * 用户id
+ */
+ private int userId = 1;
+
+ /**
+ * 用户token
+ */
+ private int token = 1;
+
+ /**
+ * Gets appId.
+ *
+ * @return the appId
+ */
+ public String getAppId() {
+ return appId;
+ }
+
+ /**
+ * Sets appId.
+ *
+ * @param appId the appId
+ */
+ public void setAppId(final String appId) {
+ this.appId = appId;
+ }
+
+ /**
+ * Gets bizId.
+ *
+ * @return the bizId
+ */
+ public String getBizId() {
+ return bizId;
+ }
+
+ /**
+ * Sets bizId.
+ *
+ * @param bizId the bizId
+ */
+ public void setBizId(final String bizId) {
+ this.bizId = bizId;
+ }
+
+ /**
+ * Gets uhId.
+ *
+ * @return the uhId
+ */
+ public String getUhId() {
+ return uhId;
+ }
+
+ /**
+ * Sets uhId.
+ *
+ * @param uhId the uhId
+ */
+ public void setUhId(final String uhId) {
+ this.uhId = uhId;
+ }
+
+ /**
+ * Gets userId.
+ *
+ * @return the userId
+ */
+ public int getUserId() {
+ return userId;
+ }
+
+ /**
+ * Sets userId.
+ *
+ * @param userId the userId
+ */
+ public void setUserId(final int userId) {
+ this.userId = userId;
+ }
+
+ /**
+ * Gets token.
+ *
+ * @return the token
+ */
+ public int getToken() {
+ return token;
+ }
+
+ /**
+ * Sets token.
+ *
+ * @param token the token
+ */
+ public void setToken(final int token) {
+ this.token = token;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("DaoContext{");
+ sb.append("appId='").append(appId).append('\'');
+ sb.append(", bizId='").append(bizId).append('\'');
+ sb.append(", uhId='").append(uhId).append('\'');
+ sb.append(", userId=").append(userId);
+ sb.append(", token=").append(token);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/muster-logic/src/main/java/com/muster/logic/BO/package-info.java b/muster-logic/src/main/java/com/muster/logic/BO/package-info.java
new file mode 100644
index 000000000..2f0aecfcc
--- /dev/null
+++ b/muster-logic/src/main/java/com/muster/logic/BO/package-info.java
@@ -0,0 +1,9 @@
+/**
+ * Description
+ *
+ *
+ * DATE 2020-07-04.
+ *
+ * @author 刘江涛.
+ */
+package com.muster.logic.BO;
diff --git a/muster-logic/src/main/java/com/muster/logic/DaoContextUtils.java b/muster-logic/src/main/java/com/muster/logic/DaoContextUtils.java
new file mode 100644
index 000000000..1833f6153
--- /dev/null
+++ b/muster-logic/src/main/java/com/muster/logic/DaoContextUtils.java
@@ -0,0 +1,39 @@
+package com.muster.logic;
+
+
+import com.muster.common.config.MusterConfig;
+import com.muster.logic.BO.DaoContext;
+import org.slf4j.MDC;
+
+import java.util.Map;
+
+/**
+ * Description
+ *
+ *
+ * DATE 2020-07-05.
+ *
+ * @author 刘江涛.
+ */
+public class DaoContextUtils {
+
+ public static DaoContext createContext() {
+ String hid = MDC.get("hid");
+ int userId = Integer.valueOf(MDC.get("userId"));
+ int token = Integer.valueOf(MDC.get("token"));
+ String appId = MusterConfig.getAppId();
+ String bizId = MusterConfig.getBizId();
+ return new DaoContext(appId, bizId, hid, userId, token);
+ }
+
+ public static DaoContext createContext(final Map params) {
+ String hid = MDC.get("hid");
+ int userId = Integer.valueOf(MDC.get("userId"));
+ int token = Integer.valueOf(MDC.get("token"));
+ String appId = String.valueOf(params.getOrDefault("appId", MusterConfig.getAppId()));
+ String bizId = String.valueOf(params.getOrDefault("bizId", MusterConfig.getBizId()));
+ params.remove("appId");
+ params.remove("bizId");
+ return new DaoContext(appId, bizId, hid, userId, token);
+ }
+}
diff --git a/muster-logic/src/main/java/com/muster/logic/DbLogicService.java b/muster-logic/src/main/java/com/muster/logic/DbLogicService.java
new file mode 100644
index 000000000..a571f4cd8
--- /dev/null
+++ b/muster-logic/src/main/java/com/muster/logic/DbLogicService.java
@@ -0,0 +1,23 @@
+package com.muster.logic;
+
+import com.muster.logic.model.ProcedureResult;
+
+import java.util.Map;
+
+/**
+ * Description
+ *
+ *
+ * DATE 2020-07-04.
+ *
+ * @author 刘江涛.
+ */
+public interface DbLogicService {
+
+ /**
+ * @param procedureName 存储过程名称,从 ProcedureNameConstants 获取
+ * @param params 存储过程参数
+ * @return 返回结果集
+ */
+ ProcedureResult exec(final String procedureName, final Map params);
+}
diff --git a/muster-logic/src/main/java/com/muster/logic/DbLogicServiceImpl.java b/muster-logic/src/main/java/com/muster/logic/DbLogicServiceImpl.java
new file mode 100644
index 000000000..4c08138f1
--- /dev/null
+++ b/muster-logic/src/main/java/com/muster/logic/DbLogicServiceImpl.java
@@ -0,0 +1,163 @@
+package com.muster.logic;
+
+import com.muster.logic.BO.DaoContext;
+import com.muster.logic.model.ProcedureResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+import javax.sql.DataSource;
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * Description
+ *
+ *
+ * DATE 2020-07-04.
+ *
+ * @author 刘江涛.
+ */
+@Service
+public class DbLogicServiceImpl implements DbLogicService {
+
+ Logger log = LoggerFactory.getLogger(DbLogicServiceImpl.class);
+
+ private DataSource dataSource;
+
+ private final static int OUPUT_INDEX = 6;
+
+ @Autowired
+ DbLogicServiceImpl(@Qualifier("masterDataSource") DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ @Override
+ public ProcedureResult exec(final String procedureName, final Map params) {
+ ProcedureResult result = new ProcedureResult();
+ DaoContext context = DaoContextUtils.createContext(params);
+ String sql = this.createProcedure(procedureName, params.size());
+
+ try (Connection conn = dataSource.getConnection();
+ CallableStatement cs = conn.prepareCall(sql)) {
+
+ // 设置上下文参数
+ this.setContext(cs, context);
+ // 设置业务参数
+ this.setParams(cs, params);
+
+ cs.registerOutParameter(6, Types.INTEGER);
+ cs.execute();
+
+ int res = cs.getInt(OUPUT_INDEX);
+ result.setRes(res);
+ if (log.isDebugEnabled()) {
+ log.debug("{}, {}, {}, {}", procedureName, context.toString(), params, res);
+ }
+ List