修改环境配置

This commit is contained in:
liujiangtao
2020-07-25 12:39:47 +08:00
parent b5b78b4fff
commit 9e73f6c52b
49 changed files with 2746 additions and 83 deletions

25
doc/info.txt Normal file
View File

@ -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)
AppIDwx08196c4219236ab5
AppSecret9a131c53016eb64e1f55161326307bbf
appIdwx08196c4219236ab5
授权回调域grow.xxzzu.com
微信开放平台open.weixin.qq.com
注册邮箱jcjytbkt@126.com
密码xx-621588+-

30
doc/xxzzu.conf Normal file
View File

@ -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;
}
}

View File

@ -73,6 +73,17 @@
<artifactId>muster-generator</artifactId>
</dependency>
<!-- 逻辑模块-->
<dependency>
<groupId>com.muster</groupId>
<artifactId>muster-logic</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -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);
// 下载名称

View File

@ -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();
}
}

View File

@ -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("微信扫码登录失败,请重试");
}
}

View File

@ -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;
}
}

View File

@ -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];
}
}

View File

@ -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;
}
}

View File

@ -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<String, String> sign(String jsapi_ticket, String url) {
Map<String, String> ret = new HashMap<String, String>();
String nonce_str = create_nonce_str();
String timestamp = create_timestamp();
String string1;
String signature = "";
//注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + jsapi_ticket +
"&noncestr=" + nonce_str +
"&timestamp=" + timestamp +
"&url=" + url;
System.out.println(string1);
try
{
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
ret.put("url", url);
ret.put("jsapi_ticket", jsapi_ticket);
ret.put("nonceStr", nonce_str);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
return ret;
}
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
private static String create_nonce_str() {
return UUID.randomUUID().toString();
}
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,19 @@
package com.muster.web.controller.muster.weixin;
/**
* Description
* <p>
* </p>
* 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);
}

View File

@ -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
* <p>
* </p>
* 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<String, Object> 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<String, Object> params) {
Map<String, Object> 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<String, Object> params) {
ProcedureResult loginRes = storedProcedure.exec(PROC_DU02A_USER_LOGIN, params);
return loginRes.getRes();
}
}

View File

@ -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;
}
}

View File

@ -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<String, JsApiTicket> weixinCache = new HashMap<String, JsApiTicket>();
private static Map<String, Token> tokenCache = new HashMap<String, Token>();
// 临时二维码
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<String, String> 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<String, String> 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<String,Integer> intMap = new HashMap<String,Integer>();
intMap.put("scene_id",sceneId);
Map<String,Map<String,Integer>> mapMap = new HashMap<String,Map<String,Integer>>();
mapMap.put("scene", intMap);
//
Map<String,Object> paramsMap = new HashMap<String,Object>();
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<String,Integer> intMap = new HashMap<String,Integer>();
intMap.put("scene_id",sceneId);
Map<String,Map<String,Integer>> mapMap = new HashMap<String,Map<String,Integer>>();
mapMap.put("scene", intMap);
//
Map<String,Object> paramsMap = new HashMap<String,Object>();
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<String,String> intMap = new HashMap<String,String>();
intMap.put("scene_str",sceneStr);
Map<String,Map<String,String>> mapMap = new HashMap<String,Map<String,String>>();
mapMap.put("scene", intMap);
Map<String,Object> paramsMap = new HashMap<String,Object>();
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<String,Object> paramsMap = new HashMap<String,Object>();
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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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}")

View File

@ -0,0 +1,11 @@
muster:
# 文件路径 示例( Windows配置D:/muster/uploadPathLinux配置 /home/muster/uploadPath
profile: /Users/liujiangtao/project/mishang/muster-vue
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 8080
servlet:
# 应用的访问路径
context-path: /

View File

@ -0,0 +1,12 @@
muster:
# 文件路径 示例( Windows配置D:/muster/uploadPathLinux配置 /home/muster/uploadPath
profile: /www/muster/upload
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 8081
servlet:
# 应用的访问路径
context-path: /prod-api

View File

@ -5,11 +5,9 @@ muster:
# 版本
version: 3.0.0
# 版权年份
copyrightYear: 2019
copyrightYear: 2020
# 实例演示开关
demoEnabled: true
# 文件路径 示例( Windows配置D:/muster/uploadPathLinux配置 /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

View File

@ -119,6 +119,12 @@
<artifactId>javax.servlet-api</artifactId>
</dependency>
<!--Hutool工具-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -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;
}
}

View File

@ -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<String, String> 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";
}
}

View File

@ -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;

View File

@ -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
{

View File

@ -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<T>
*/
public String getAbsoluteFile(String filename)
{
String downloadPath = RuoYiConfig.getDownloadPath() + filename;
String downloadPath = MusterConfig.getDownloadPath() + filename;
File desc = new File(downloadPath);
if (!desc.getParentFile().exists())
{

View File

@ -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/");

View File

@ -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)
{

View File

@ -200,7 +200,7 @@ public class GenUtils
*/
public static String replaceText(String text)
{
return RegExUtils.replaceAll(text, "(?:表|若依)", "");
return RegExUtils.replaceAll(text, "(?:表|muster)", "");
}
/**

23
muster-logic/pom.xml Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>muster</artifactId>
<groupId>com.muster</groupId>
<version>3.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>muster-logic</artifactId>
<version>3.0.0</version>
<dependencies>
<!-- 核心模块-->
<dependency>
<groupId>com.muster</groupId>
<artifactId>muster-framework</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,150 @@
package com.muster.logic.BO;
/**
* Description
* <p>
* </p>
* 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();
}
}

View File

@ -0,0 +1,9 @@
/**
* Description
* <p>
* </p>
* DATE 2020-07-04.
*
* @author 刘江涛.
*/
package com.muster.logic.BO;

View File

@ -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
* <p>
* </p>
* 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<String, Object> 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);
}
}

View File

@ -0,0 +1,23 @@
package com.muster.logic;
import com.muster.logic.model.ProcedureResult;
import java.util.Map;
/**
* Description
* <p>
* </p>
* DATE 2020-07-04.
*
* @author 刘江涛.
*/
public interface DbLogicService {
/**
* @param procedureName 存储过程名称,从 ProcedureNameConstants 获取
* @param params 存储过程参数
* @return 返回结果集
*/
ProcedureResult exec(final String procedureName, final Map<String, Object> params);
}

View File

@ -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
* <p>
* </p>
* 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<String, Object> 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<Map<String, Object>> list = this.getResult(cs);
result.setResult(list);
} catch (SQLException e) {
log.error("{}, {}, {}", procedureName, context.toString(), params, e);
}
return result;
}
private List<Map<String, Object>> getResult(final CallableStatement cs) {
List<Map<String, Object>> list = new ArrayList<>();
try (ResultSet rs = cs.getResultSet();) {
if (Objects.isNull(rs)) {
return list;
}
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
while (rs.next()) {
Map<String, Object> map = new HashMap<>();
for (int i = 1; i <= columnCount; i++) {
String name = rsmd.getColumnName(i);
String type = rsmd.getColumnClassName(i);
Object value = null;
if ("java.lang.String".equals(type)) {
value = rs.getString(i);
} else if ("java.lang.Integer".equals(type)) {
value = rs.getInt(i);
} else if ("java.sql.Date".equals(type)) {
value = rs.getDate(i);
} else if ("java.math.BigDecimal".equals(type)) {
value = rs.getBigDecimal(i);
} else if ("java.lang.Boolean".equals(type)) {
value = rs.getBoolean(i);
} else if ("java.lang.Long".equals(type)) {
value = rs.getLong(i);
} else if ("java.sql.Timestamp".equals(type)) {
value = rs.getTimestamp(i);
}
map.put(name, value);
}
list.add(map);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
private void setParams(final CallableStatement cs, final Map<String, Object> params) {
int index = 7;
List<String> keys = params.keySet().stream().sorted().collect(Collectors.toList());
for (int i = 0; i < keys.size(); i++) {
setParam(cs, params, keys.get(i), index);
index++;
}
}
private void setParam(final CallableStatement cs, final Map<String, Object> params, final String key,
final int index) {
Object v = params.get(key);
try {
if (v instanceof String) {
cs.setString(index, v.toString());
} else if (v instanceof Integer) {
cs.setInt(index, Integer.valueOf(v.toString()));
} else if (v instanceof Double) {
cs.setDouble(index, Double.valueOf(v.toString()));
}
} catch (SQLException e) {
}
}
private void setContext(final CallableStatement cs, final DaoContext context) throws SQLException {
cs.setString(1, context.getAppId());
cs.setString(2, context.getBizId());
cs.setString(3, context.getUhId());
cs.setInt(4, context.getUserId());
cs.setInt(5, context.getToken());
}
private String createProcedure(final String name, final int size) {
StringBuilder str = new StringBuilder();
for (int i = 0; i < size; i++) {
str.append(" ,?");
}
return String.format(procedureTemplate, name, str.toString());
}
private final static String procedureTemplate = "call %s(?, ?, ?, ?, ?, ?%s)";
}

View File

@ -0,0 +1,64 @@
package com.muster.logic.model;
import java.util.List;
import java.util.Map;
/**
* Description
* <p>
* </p>
* DATE 2020-07-04.
*
* @author 刘江涛.
*/
public class ProcedureResult {
private int res;
private List<Map<String, Object>> result;
/**
* Gets res.
*
* @return the res
*/
public int getRes() {
return res;
}
/**
* Sets res.
*
* @param res the res
*/
public void setRes(final int res) {
this.res = res;
}
/**
* Gets result.
*
* @return the result
*/
public List<Map<String, Object>> getResult() {
return result;
}
/**
* Sets result.
*
* @param result the result
*/
public void setResult(final List<Map<String, Object>> result) {
this.result = result;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("ProcedureResult{");
sb.append("res=").append(res);
sb.append(", result=").append(result);
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,9 @@
/**
* Description
* <p>
* </p>
* DATE 2020-07-04.
*
* @author 刘江涛.
*/
package com.muster.logic.model;

View File

@ -0,0 +1,9 @@
/**
* Description
* <p>
* </p>
* DATE 2020-07-04.
*
* @author 刘江涛.
*/
package com.muster.logic;

View File

@ -1,8 +1,8 @@
{
"name": "muster",
"version": "3.0.0",
"description": "若依管理系统",
"author": "若依",
"description": "Muster管理系统",
"author": "MUster",
"license": "MIT",
"scripts": {
"dev": "vue-cli-service serve --open",

View File

@ -1,31 +1,31 @@
module.exports = {
title: '若依管理系统',
/**
* 是否系统布局配置
*/
showSettings: false,
/**
* 是否显示 tagsView
*/
tagsView: true,
/**
* 是否固定头部
*/
fixedHeader: false,
/**
* 是否显示logo
*/
sidebarLogo: true,
/**
* @type {string | array} 'production' | ['production', 'development']
* @description Need show err logs component.
* The default is only used in the production env
* If you want to also use it in dev, you can pass ['production', 'development']
*/
errorLog: 'production'
}
module.exports = {
title: 'Muster管理系统',
/**
* 是否系统布局配置
*/
showSettings: false,
/**
* 是否显示 tagsView
*/
tagsView: true,
/**
* 是否固定头部
*/
fixedHeader: false,
/**
* 是否显示logo
*/
sidebarLogo: true,
/**
* @type {string | array} 'production' | ['production', 'development']
* @description Need show err logs component.
* The default is only used in the production env
* If you want to also use it in dev, you can pass ['production', 'development']
*/
errorLog: 'production'
}

86
muster.sh Executable file
View File

@ -0,0 +1,86 @@
#!/bin/bash
AppName=muster-admin.jar
#JVM参数
JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
APP_HOME=`pwd`
LOG_PATH=$APP_HOME/logs/$AppName.log
if [ "$1" = "" ];
then
echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m"
exit 1
fi
if [ "$AppName" = "" ];
then
echo -e "\033[0;31m 未输入应用名 \033[0m"
exit 1
fi
function start()
{
PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
if [ x"$PID" != x"" ]; then
echo "$AppName is running..."
else
nohup java -jar $JVM_OPTS target/$AppName > /dev/null 2>&1 &
echo "Start $AppName success..."
fi
}
function stop()
{
echo "Stop $AppName"
PID=""
query(){
PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
}
query
if [ x"$PID" != x"" ]; then
kill -TERM $PID
echo "$AppName (pid:$PID) exiting..."
while [ x"$PID" != x"" ]
do
sleep 1
query
done
echo "$AppName exited."
else
echo "$AppName already stopped."
fi
}
function restart()
{
stop
sleep 2
start
}
function status()
{
PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l`
if [ $PID != 0 ];then
echo "$AppName is running..."
else
echo "$AppName is not running..."
fi
}
case $1 in
start)
start;;
stop)
stop;;
restart)
restart;;
status)
status;;
*)
esac

25
pom.xml
View File

@ -30,6 +30,8 @@
<poi.version>3.17</poi.version>
<velocity.version>1.7</velocity.version>
<jwt.version>0.9.0</jwt.version>
<hutool.version>5.2.1</hutool.version>
<gson.version>2.8.5</gson.version>
</properties>
<!-- 依赖声明 -->
@ -181,6 +183,28 @@
<version>${muster.version}</version>
</dependency>
<!-- 逻辑模块 -->
<dependency>
<groupId>com.muster</groupId>
<artifactId>muster-logic</artifactId>
<version>${muster.version}</version>
</dependency>
<!--Hutool工具-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
@ -191,6 +215,7 @@
<module>muster-quartz</module>
<module>muster-generator</module>
<module>muster-common</module>
<module>muster-logic</module>
</modules>
<packaging>pom</packaging>

View File

@ -23,16 +23,16 @@ create table sys_dept (
-- ----------------------------
-- 初始化-部门表数据
-- ----------------------------
insert into sys_dept values(100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(100, 0, '0', '若依科技', 0, 'muster', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(101, 100, '0,100', '深圳总公司', 1, 'muster', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(102, 100, '0,100', '长沙分公司', 2, 'muster', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(103, 101, '0,100,101', '研发部门', 1, 'muster', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(104, 101, '0,100,101', '市场部门', 2, 'muster', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(105, 101, '0,100,101', '测试部门', 3, 'muster', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(106, 101, '0,100,101', '财务部门', 4, 'muster', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(107, 101, '0,100,101', '运维部门', 5, 'muster', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(108, 102, '0,100,102', '市场部门', 1, 'muster', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
insert into sys_dept values(109, 102, '0,100,102', '财务部门', 2, 'muster', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
-- ----------------------------
@ -65,8 +65,8 @@ create table sys_user (
-- ----------------------------
-- 初始化-用户信息表数据
-- ----------------------------
insert into sys_user values(1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '管理员');
insert into sys_user values(2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '测试员');
insert into sys_user values(1, 103, 'admin', 'muster', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '管理员');
insert into sys_user values(2, 105, 'ry', 'muster', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '测试员');
-- ----------------------------