微信相关api

This commit is contained in:
Qi 2025-05-21 10:11:35 +08:00
parent 50ac53221b
commit 27e6d67c37
29 changed files with 733 additions and 380 deletions

View File

@ -0,0 +1,81 @@
package org.jeecg.modules.contoller.h5;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.entity.Oauth2UserInfoRes;
import org.jeecg.modules.service.WeChantService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
/**
* 微信网页授权相关
*/
@RestController
@RequestMapping("/h5/wechat")
@Api(tags = {"微信网页授权"})
@RequiredArgsConstructor
@Slf4j
public class WeChantController {
@Autowired
private WeChantService weChantService;
/**
* 由后端来进行授权操作需要在微信页面打开
*
* @param baseUrl 前端页面地址 用于授权完成后后端重定向到前端页面
* @param scope 应用授权作用域此处为了模拟两种情况进行传值:
* snsapi_base 不弹出授权页面直接跳转只能获取用户openid
* snsapi_userinfo 弹出授权页面可通过 openid 拿到昵称性别所在地 即使在未关注的情况下只要用户授权也能获取其信息
* @return
*/
@GetMapping(value = "/code")
@ApiOperation(value = "用户请求进行授权及获取信息", notes = "用户请求进行授权及获取信息")
public Result<?> code(@RequestParam("baseUrl") String baseUrl, String scope) throws UnsupportedEncodingException {
log.info("------ 用户请求进行授权及获取信息 ------");
//通过code获取用户其信息
String url = weChantService.getAuthCode(baseUrl, scope);
return Result.ok("redirect:" + url);
}
/**
* @param code
* @param state 存放的前端页面地址授权后回调用
* @return
*/
@GetMapping(value = "/auth")
@ApiOperation(value = "前端根据code获取信息", notes = "前端根据code获取信息")
public Result<?> auth(@RequestParam(value = "code", required = false) String code, @RequestParam(value = "state", required = false) String state) throws IOException {
log.info("------ 回显Code{} ------", code);
JSONObject data = new JSONObject();
// 解析回传的 state值
state = new String(Base64.getDecoder().decode(state.getBytes(StandardCharsets.UTF_8)));
Map map = JSON.parseObject(state, Map.class);
String baseUrl = map.get("baseUrl").toString();
data.put("baseUrl", baseUrl);
String scope = map.get("scope").toString();
// 通过code获取用户openid
Oauth2UserInfoRes userInfo = weChantService.getUserAuth(code, scope);
data.put("userInfo", userInfo);
// 直接跳转到前端地址
return Result.ok(data);
}
@PostMapping("/AutocheckUser")
public Result<?> AutocheckUser(@RequestBody Map<String, String> request) {
String openId = request.get("openId");
return Result.ok(weChantService.AutocheckUser(openId));
}
}

View File

@ -1,135 +0,0 @@
package org.jeecg.modules.contoller.h5;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.entity.WxH5OuthrizeForm;
import org.jeecg.modules.entity.WxUser;
import org.jeecg.modules.utils.Constant;
import org.jeecg.modules.utils.CookieUtil;
import org.jeecg.modules.utils.MD5Util;
import org.jeecg.modules.utils.SHA1Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
/**
* 微信网页授权相关
*/
@RestController
@RequestMapping("/wxAuth")
@Api(tags = {"微信网页授权"})
@RequiredArgsConstructor
public class WxAuthController {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private final WxMpService wxMpService;
/**
* 使用微信授权code换取openid
*
* @param request
* @param response
* @param form
* @return
*/
@PostMapping("/codeToOpenid")
@CrossOrigin
@ApiOperation(value = "网页登录-code换取openid",notes = "scope为snsapi_base")
public Result<?> codeToOpenid(HttpServletRequest request, HttpServletResponse response,
@CookieValue String appid, @RequestBody WxH5OuthrizeForm form) {
try {
this.wxMpService.switchoverTo(appid);
WxOAuth2AccessToken token = wxMpService.getOAuth2Service().getAccessToken(form.getCode());
String openid = token.getOpenId();
CookieUtil.setCookie(response, "openid", openid, 365 * 24 * 60 * 60);
String openidToken = MD5Util.getMd5AndSalt(openid);
CookieUtil.setCookie(response, "openidToken", openidToken, 365 * 24 * 60 * 60);
return Result.ok(openid);
} catch (WxErrorException e) {
logger.error("code换取openid失败", e);
return Result.error(e.getError().getErrorMsg());
}
}
/**
* 使用微信授权code换取用户信息(需scope为 snsapi_userinfo)
*
* @param request
* @param response
* @param form
* @return
*/
@PostMapping("/codeToUserInfo")
@CrossOrigin
@ApiOperation(value = "网页登录-code换取用户信息",notes = "需scope为 snsapi_userinfo")
public Result codeToUserInfo(HttpServletRequest request, HttpServletResponse response,
@CookieValue String appid, @RequestBody WxH5OuthrizeForm form) {
try {
this.wxMpService.switchoverTo(appid);
WxOAuth2AccessToken token = wxMpService.getOAuth2Service().getAccessToken(form.getCode());
WxOAuth2UserInfo userInfo = wxMpService.getOAuth2Service().getUserInfo(token,"zh_CN");
String openid = userInfo.getOpenid();
CookieUtil.setCookie(response, "openid", openid, 365 * 24 * 60 * 60);
String openidToken = MD5Util.getMd5AndSalt(openid);
CookieUtil.setCookie(response, "openidToken", openidToken, 365 * 24 * 60 * 60);
return Result.ok(new WxUser(userInfo,appid));
} catch (WxErrorException e) {
logger.error("code换取用户信息失败", e);
return Result.error(e.getError().getErrorMsg());
}
}
/**
* 获取微信分享的签名配置
* 允许跨域只有微信公众号添加了js安全域名的网站才能加载微信分享故这里不对域名进行校验
*
* @param request
* @param response
* @return
*/
@GetMapping("/getShareSignature")
@ApiOperation(value = "获取微信分享的签名配置",notes = "微信公众号添加了js安全域名的网站才能加载微信分享")
public Result getShareSignature(HttpServletRequest request, HttpServletResponse response, @CookieValue String appid) throws WxErrorException {
this.wxMpService.switchoverTo(appid);
// 1.拼接url当前网页的URL不包含#及其后面部分
String wxShareUrl = request.getHeader(Constant.WX_CLIENT_HREF_HEADER);
if (!StringUtils.hasText(wxShareUrl)) {
return Result.error("header中缺少"+Constant.WX_CLIENT_HREF_HEADER+"参数,微信分享加载失败");
}
wxShareUrl = wxShareUrl.split("#")[0];
Map<String, String> wxMap = new TreeMap<>();
String wxNoncestr = UUID.randomUUID().toString();
String wxTimestamp = (System.currentTimeMillis() / 1000) + "";
wxMap.put("noncestr", wxNoncestr);
wxMap.put("timestamp", wxTimestamp);
wxMap.put("jsapi_ticket", wxMpService.getJsapiTicket());
wxMap.put("url", wxShareUrl);
// 加密获取signature
StringBuilder wxBaseString = new StringBuilder();
wxMap.forEach((key, value) -> wxBaseString.append(key).append("=").append(value).append("&"));
String wxSignString = wxBaseString.substring(0, wxBaseString.length() - 1);
// signature
String wxSignature = SHA1Util.sha1(wxSignString);
Map<String, String> resMap = new TreeMap<>();
resMap.put("appId", appid);
resMap.put("wxTimestamp", wxTimestamp);
resMap.put("wxNoncestr", wxNoncestr);
resMap.put("wxSignature", wxSignature);
return Result.ok(resMap);
}
}

View File

@ -50,7 +50,7 @@ public class h5CeesUserController {
}
@GetMapping("/getGroupName")
public Result<?> getGroupName(@RequestParam String groupId){
public Result<?> getGroupName(@RequestParam(required = false) String groupId){
return ceesUserService.getGroupName(groupId);
}
@GetMapping(value="/getH5Time")

View File

@ -18,7 +18,7 @@ public class h5WaiTeacherController {
return ceesWaiTeacherService.h5Save(ceesWaiTeacher);
}
@GetMapping("/getDormitoryName")
public Result<?> getDormitoryName(@RequestParam String dormitoryId) {
public Result<?> getDormitoryName(@RequestParam(required = false) String dormitoryId) {
return ceesWaiTeacherService.getDormitoryName(dormitoryId);
}
}

View File

@ -23,7 +23,7 @@ import java.util.Date;
* @Version: V1.0
*/
@Data
@TableName("cees_local_teacher")
@TableName("cees_local_teacher_test")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="cees_local_teacher对象", description="本校教师表")
@ -34,6 +34,10 @@ public class CeesLocalTeacher implements Serializable {
@TableId(type = IdType.ASSIGN_ID)
@ApiModelProperty(value = "主键")
private String id;
/**
* openid
*/
private String openId;
/**创建人*/
@ApiModelProperty(value = "创建人")
private String createBy;

View File

@ -23,7 +23,7 @@ import java.time.LocalDateTime;
* @Version: V1.0
*/
@Data
@TableName("cees_user")
@TableName("cees_user_test")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="cees_user对象", description="CEES用户表")
@ -34,6 +34,12 @@ public class CeesUser implements Serializable {
@TableId(type = IdType.ASSIGN_ID)
@ApiModelProperty(value = "主键")
private String id;
/**
* openid
*/
private String openId;
/**创建人*/
@ApiModelProperty(value = "创建人")
private String createBy;

View File

@ -23,7 +23,7 @@ import java.util.Date;
* @Version: V1.0
*/
@Data
@TableName("cees_wai_teacher")
@TableName("cees_wai_teacher_test")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="cees_wai_teacher对象", description="外校老师管理")
@ -34,6 +34,10 @@ public class CeesWaiTeacher implements Serializable {
@TableId(type = IdType.ASSIGN_ID)
@ApiModelProperty(value = "主键")
private String id;
/**
* openid
*/
private String openId;
/**创建人*/
@ApiModelProperty(value = "创建人")
private String createBy;

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.entity;
public interface InterfaceConstant {
/**
* 用户同意授权获取code
*/
String OAUTH2_AUTHORIZE = "connect/oauth2/authorize";
/**
* 通过 code 换取网页授权access_token
*/
String OAUTH2_ACCESS_TOKEN = "sns/oauth2/access_token";
/**
* 获取用户信息
*/
String OAUTH2_USERINFO = "sns/userinfo";
}

View File

@ -0,0 +1,27 @@
package org.jeecg.modules.entity;
import lombok.Data;
@Data
public class Oauth2AccessTokenRep {
/**
* 公众号的唯一标识
*/
private String appid;
/**
* 公众号的appsecret
*/
private String secret;
/**
* 填写第一步获取的 code 参数
*/
private String code;
/**
* 填写为authorization_code
*/
private String grant_type = "authorization_code";
}

View File

@ -0,0 +1,42 @@
package org.jeecg.modules.entity;
import lombok.Data;
@Data
public class Oauth2AccessTokenRes {
/**
* 网页授权接口调用凭证,注意此access_token与基础支持的access_token不同
*/
private String access_token;
/**
* access_token接口调用凭证超时时间单位
*/
private Integer expires_in;
/**
* 用户刷新access_token
*/
private String refresh_token;
/**
* 用户唯一标识请注意在未关注公众号时用户访问公众号的网页也会产生一个用户和公众号唯一的OpenID
*/
private String openid;
/**
* 用户授权的作用域使用逗号,分隔
*/
private String scope;
/**
* 是否为快照页模式虚拟账号只有当用户是快照页模式虚拟账号时返回值为1
*/
private String is_snapshotuser;
/**
* 用户统一标识针对一个微信开放平台帐号下的应用同一用户的 unionid 是唯一的只有当 scope "snsapi_userinfo"时返回
* 并且公众号与微信开放平台进行了绑定才会返回
*/
private String unionid;
}

View File

@ -0,0 +1,32 @@
package org.jeecg.modules.entity;
import lombok.Data;
@Data
public class Oauth2AuthorizeRep {
/**
* 公众号的唯一标识
*/
private String appid;
/**
* 授权后重定向的回调链接地址 请使用 urlEncode 对链接进行处理
*/
private String redirect_uri;
/**
* 返回类型请填写code
*/
private String response_type = "code";
/**
* 应用授权作用域snsapi_base 不弹出授权页面直接跳转只能获取用户openid
* snsapi_userinfo 弹出授权页面可通过 openid 拿到昵称性别所在地并且 即使在未关注的情况下只要用户授权也能获取其信息
*/
private String scope;
/**
* 重定向后会带上 state 参数开发者可以填写a-zA-Z0-9的参数值最多128字节
*/
private String state;
}

View File

@ -0,0 +1,23 @@
package org.jeecg.modules.entity;
import lombok.Data;
@Data
public class Oauth2UserInfoRep {
/**
* 网页授权接口调用凭证,注意此access_token与基础支持的access_token不同
*/
private String access_token;
/**
* 用户的唯一标识
*/
private String openid;
/**
* 返回国家地区语言版本zh_CN 简体zh_TW 繁体en 英语
*/
private String lang = "zh_CN";
}

View File

@ -0,0 +1,55 @@
package org.jeecg.modules.entity;
import lombok.Data;
import java.util.List;
@Data
public class Oauth2UserInfoRes {
/**
* 用户昵称
*/
private String nickname;
/**
* 用户的唯一标识
*/
private String openid;
/**
* 用户的性别值为1时是男性值为2时是女性值为0时是未知
*/
private Integer sex;
/**
* 用户个人资料填写的省份
*/
private String province;
/**
* 普通用户个人资料填写的城市
*/
private String city;
/**
* 国家如中国为CN
*/
private String country;
/**
* 用户头像最后一个数值代表正方形头像大小有0466496132数值可选0代表640*640正方形头像
* 用户没有头像时该项为空若用户更换头像原有头像 URL 将失效
*/
private String headimgurl;
/**
* 用户特权信息json 数组如微信沃卡用户为chinaunicom
*/
private List<String> privilege;
/**
* 只有在用户将公众号绑定到微信开放平台帐号后才会出现该字段
*/
private String unionid;
}

View File

@ -23,7 +23,7 @@ import java.util.Date;
* @Version: V1.0
*/
@Data
@TableName("cees_student")
@TableName("cees_student_test")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="student对象", description="研究生表")
@ -34,6 +34,10 @@ public class Student implements Serializable {
@TableId(type = IdType.ASSIGN_ID)
@ApiModelProperty(value = "主键")
private String id;
/**
* openid
*/
private String openId;
/**创建人*/
@ApiModelProperty(value = "创建人")
private String createBy;

View File

@ -1,16 +0,0 @@
package org.jeecg.modules.entity;
import lombok.Data;
import org.jeecg.modules.utils.Json;
import javax.validation.constraints.NotEmpty;
@Data
public class WxH5OuthrizeForm {
@NotEmpty(message = "code不得为空")
private String code;
@Override
public String toString() {
return Json.toJsonString(this);
}
}

View File

@ -1,85 +0,0 @@
package org.jeecg.modules.entity;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import lombok.Data;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.jeecg.modules.utils.Json;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.Date;
/**
* 微信粉丝
* @author Nifury
* @date 2017-9-27
*/
@Data
@TableName("cees_wx_user")
public class WxUser implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.INPUT)
private String openid;
private String appid;
private String phone;
private String nickname;
private int sex;
private String city;
private String province;
private String headimgurl;
@JSONField(name = "subscribe_time")
private Date subscribeTime;
private boolean subscribe;
private String unionid;
private String remark;
private JSONArray tagidList;
private String subscribeScene;
private String qrSceneStr;
public WxUser() {
}
public WxUser(String openid) {
this.openid = openid;
}
public WxUser(WxMpUser wxMpUser,String appid) {
this.openid = wxMpUser.getOpenId();
this.appid = appid;
this.subscribe=wxMpUser.getSubscribe();
if(wxMpUser.getSubscribe()){
this.nickname = wxMpUser.getNickname();
this.headimgurl = wxMpUser.getHeadImgUrl();
this.subscribeTime = new Date(wxMpUser.getSubscribeTime()*1000);
this.unionid=wxMpUser.getUnionId();
this.remark=wxMpUser.getRemark();
this.tagidList=JSONArray.parseArray(JSONObject.toJSONString(wxMpUser.getTagIds()));
this.subscribeScene=wxMpUser.getSubscribeScene();
String qrScene = wxMpUser.getQrScene();
this.qrSceneStr= !StringUtils.hasText(qrScene) ? wxMpUser.getQrSceneStr() : qrScene;
}
}
public WxUser(WxOAuth2UserInfo wxMpUser, String appid) {
this.openid = wxMpUser.getOpenid();
this.appid = appid;
this.subscribe=wxMpUser.getNickname()!=null;
if(this.subscribe){
this.nickname = wxMpUser.getNickname();
this.headimgurl = wxMpUser.getHeadImgUrl();
this.unionid=wxMpUser.getUnionId();
}
}
@Override
public String toString() {
return Json.toJsonString(this);
}
}

View File

@ -30,4 +30,5 @@ public interface ICeesUserService extends IService<CeesUser> {
Result<?> createAccount(CreateAccountDto createAccountDto);
Result<?> getH5Time();
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.service;
import com.alibaba.fastjson.JSONObject;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.entity.Oauth2UserInfoRes;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
public interface WeChantService {
String getAuthCode(String baseUrl, String scope) throws UnsupportedEncodingException;
Oauth2UserInfoRes getUserAuth(String code, String scope) throws IOException;
Result<?> AutocheckUser(String openId);
}

View File

@ -133,7 +133,12 @@ public class CeesUserServiceImpl extends ServiceImpl<CeesUserMapper, CeesUser> i
jsonObject.put("status", "2"); //无需填写信息
return Result.ok(jsonObject);
} else {
return Result.error("管理员账号还未申请通过!");
JSONObject jsonObject = new JSONObject();
jsonObject.put("userId", user.getUserId());
jsonObject.put("router", "/leaderShip");
jsonObject.put("status", "2"); //无需填写信息
return Result.ok(jsonObject);
// return Result.error("管理员账号还未申请通过!");
}
// 2学生
case "2":
@ -282,7 +287,16 @@ public class CeesUserServiceImpl extends ServiceImpl<CeesUserMapper, CeesUser> i
*/
@Override
public Result<?> getGroupName(String groupId) {
return Result.ok(ceesGroupMapper.selectById(groupId).getName());
if (groupId == null || groupId.trim().isEmpty()) {
return Result.ok("暂时未分组");
} else {
if (ceesGroupMapper.selectById(groupId).getName() == null) {
return Result.ok("暂时未分组");
} else {
return Result.ok(ceesGroupMapper.selectById(groupId).getName());
}
}
}
/**
@ -363,6 +377,8 @@ public class CeesUserServiceImpl extends ServiceImpl<CeesUserMapper, CeesUser> i
return Result.ok(cesH5Time);
}
// 获取生成规则---用户前端获取rule
public Result<?> getGenerativeRules() {
LambdaQueryWrapper<CeesGenerativeRules> queryWrapper = new LambdaQueryWrapper<>();

View File

@ -172,8 +172,10 @@ public class CeesWaiTeacherServiceImpl extends ServiceImpl<CeesWaiTeacherMapper,
ceesWaiTeacher.setGroupId(ceesUser.getGroupId());
ceesWaiTeacher.setMajorId(ceesUser.getMajorId());
ceesWaiTeacher.setUserMajorId(ceesUser.getUserMajorId());
ceesWaiTeacher.setOpenId(ceesWaiTeacher.getOpenId());
this.save(ceesWaiTeacher);
ceesUser.setUserName(ceesWaiTeacher.getUserName());
ceesUser.setOpenId(ceesWaiTeacher.getOpenId());
ceesUserMapper.updateById(ceesUser);
// TODO 邀请函的更新
@ -193,7 +195,15 @@ public class CeesWaiTeacherServiceImpl extends ServiceImpl<CeesWaiTeacherMapper,
*/
@Override
public Result<?> getDormitoryName(String dormitoryId) {
return Result.ok(ceesDormitoryInfoMapper.selectById(dormitoryId).getDormitory());
if (dormitoryId == null || dormitoryId.trim().isEmpty()) {
return Result.ok("暂时未分配");
}else{
if (ceesDormitoryInfoMapper.selectById(dormitoryId) == null) {
return Result.ok("暂时未分配");
} else {
return Result.ok(ceesDormitoryInfoMapper.selectById(dormitoryId).getDormitory());
}
}
}
@Override

View File

@ -0,0 +1,234 @@
package org.jeecg.modules.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.entity.*;
import org.jeecg.modules.mapper.*;
import org.jeecg.modules.service.WeChantService;
import org.jeecg.modules.utils.HttpclientUtils;
import org.jeecg.modules.utils.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Service
public class WeChantServiceImpl implements WeChantService {
@Autowired
private CeesUserMapper ceesUserMapper;
@Autowired
private CeesAdminInfoMapper ceesAdminInfoMapper;
@Autowired
private CeesLocalTeacherMapper ceesLocalTeacherMapper;
@Autowired
private CeesWaiTeacherMapper ceesWaiTeacherMapper;
@Autowired
private StudentMapper studentMapper;
@Value("${wx.appid}")
private String appid;
@Value("${wx.secret}")
private String secret;
@Value("${wx.apiUrl}")
private String apiUrl;
@Value("${wx.openApiUrl}")
private String openApiUrl;
@Value("${wx.authRedirectUri}")
private String authRedirectUri;
/**
* 获取用户授权码
*
* @param baseUrl
* @param scope
* @return
*/
@Override
public String getAuthCode(String baseUrl, String scope) throws UnsupportedEncodingException {
// 设置回调地址 http://6uks3d.natappfree.cc/wechat/auth该地址为后端地址
// urlEncode处理
String redirectUri = URLEncoder.encode(authRedirectUri, "utf-8");
// 组装url在url中让state属性存方baseUrl的值
String url = openApiUrl + InterfaceConstant.OAUTH2_AUTHORIZE;
// 封装url请求参数
Oauth2AuthorizeRep rep = new Oauth2AuthorizeRep();
rep.setAppid(appid);
rep.setRedirect_uri(redirectUri);
rep.setScope(scope);
// 设置回调参数需要进行urlEncode处理
Map<String, String> stateMap = new HashMap<>(4);
stateMap.put("baseUrl", baseUrl);
stateMap.put("scope", scope);
String stateMapStr = JSON.toJSONString(stateMap);
stateMapStr = new String(Base64.getEncoder().encode(stateMapStr.getBytes(StandardCharsets.UTF_8)));
rep.setState(stateMapStr);
// 参数的顺序必须是appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
url = url + MapUtils.getUrlByBean(rep) + "#wechat_redirect";
// 重定向url微信会自动访问redirectUri进行回调
return url;
}
/**
* 用户授权并且返回openid返回给前端
*
* @param code
* @param scope
* @return
*/
@Override
public Oauth2UserInfoRes getUserAuth(String code, String scope) throws IOException {
String url = apiUrl + InterfaceConstant.OAUTH2_ACCESS_TOKEN;
// 封装url请求参数
Oauth2AccessTokenRep rep = new Oauth2AccessTokenRep();
rep.setAppid(appid);
if(secret.isEmpty()){
}else {
rep.setSecret(secret);
}
rep.setCode(code);
url = url + MapUtils.getUrlByBean(rep);
JSONObject jsonObject = HttpclientUtils.doGet(url);
if (jsonObject == null) {
throw new RuntimeException("授权失败!");
}
Oauth2AccessTokenRes res = new Oauth2AccessTokenRes();
MapUtils.mapToEntity(jsonObject, res);
log.info("Oauth2AccessTokenRes" + JSON.toJSONString(res));
// 获取access_token过期时间
// long expiresToken = res.getExpires_in() - 100;
String access_token = res.getAccess_token();
String openid = res.getOpenid();
log.info("------ access_token{} ------", access_token);
log.info("------ openid{} ------", openid);
String SNS_API_USERINFO = "snsapi_userinfo";
Oauth2UserInfoRes userInfo = new Oauth2UserInfoRes();
// 根据openid和access_token获取用户信息如果"snsapi_userinfo"授权方式再调用接口获取用户信息
if (scope.equals(SNS_API_USERINFO)) {
userInfo = getAndInsertUserInfo(openid, access_token);
return userInfo;
}else {
userInfo.setOpenid(openid);
return userInfo;
}
}
private Oauth2UserInfoRes getAndInsertUserInfo(String openid, String accessToken) throws IOException {
// 获取用户信息
String url = apiUrl + InterfaceConstant.OAUTH2_USERINFO;
Oauth2UserInfoRep rep = new Oauth2UserInfoRep();
rep.setAccess_token(accessToken);
rep.setOpenid(openid);
url = url + MapUtils.getUrlByBean(rep);
JSONObject jsonObject = HttpclientUtils.doGet(url);
Oauth2UserInfoRes res = new Oauth2UserInfoRes();
MapUtils.mapToEntity(jsonObject, res);
// 打印信息
log.info("UserInfo" + JSON.toJSONString(res));
return res;
}
@Override
public Result<?> AutocheckUser(String openId) {
// /**
// * 1.按照openid来查询当前用户的账号和身份
// * 2.如果账号存在则直接进入到主页面如果不存在让用户输入信息
// */
LambdaQueryWrapper<CeesUser> ceesUserQuery = new LambdaQueryWrapper<>();
ceesUserQuery.eq(CeesUser::getOpenId, openId);
CeesUser user = ceesUserMapper.selectOne(ceesUserQuery);
// //TODO:未处理
if (user == null) {
// 说明还没注册过-把他引导去填写身份识别码
return Result.ok("/home");
}
String userId = user.getUserId();
Integer identity = user.getIdentity();
// 检查四个身份
switch (identity) {
// 管理员2 学生3老师 6 外校老师9
case 1:
LambdaQueryWrapper<CeesAdminInfo> H5AdminInfoWreapper = new LambdaQueryWrapper<>();
H5AdminInfoWreapper.eq(CeesAdminInfo::getUserId, userId);
CeesAdminInfo ceesAdminInfo = ceesAdminInfoMapper.selectOne(H5AdminInfoWreapper);
if (ceesAdminInfo != null) {
// 返回整个user
HashMap<String, Object> map = new HashMap<>();
map.put("user", ceesAdminInfo);
map.put("status", "2"); //填写过信息
map.put("router", "/leaderShip");
return Result.ok(map);
} else {
return Result.ok("/home");
}
//学生2
case 2:
// 如果openid空
LambdaQueryWrapper<Student> stuWrapper = new LambdaQueryWrapper<>();
stuWrapper.eq(Student::getOpenId, openId);
stuWrapper.eq(Student::getUserId, userId);
Student student = studentMapper.selectOne(stuWrapper);
if (student != null && student.getOpenId().equals(openId)) {
HashMap<String, Object> map = new HashMap<>();
map.put("user", student);
map.put("major", user.getMajorId());
map.put("status", "2"); //填写过信息
map.put("router", "/mainPage");
return Result.ok(map);
} else {
return Result.ok("/home");
}
//老师3
case 3:
LambdaQueryWrapper<CeesLocalTeacher> teachWrapper = new LambdaQueryWrapper<>();
teachWrapper.eq(CeesLocalTeacher::getOpenId, openId);
teachWrapper.eq(CeesLocalTeacher::getUserId, userId);
CeesLocalTeacher h5LocalTeacher = ceesLocalTeacherMapper.selectOne(teachWrapper);
if (h5LocalTeacher != null && h5LocalTeacher.getOpenId().equals(openId)) {
// 说明已经填写过个人信息了直接放行到主页面
// 返回整个user
HashMap<String, Object> map = new HashMap<>();
map.put("user", h5LocalTeacher);
map.put("major", user.getMajorId());
map.put("status", "2"); //填写过信息
map.put("router", "/mainPage");
return Result.ok(map);
} else {
return Result.ok("/home");
}
//外校老师4
case 4:
LambdaQueryWrapper<CeesWaiTeacher> h5WaiTeacherWrapper = new LambdaQueryWrapper<>();
h5WaiTeacherWrapper.eq(CeesWaiTeacher::getOpenId, openId);
h5WaiTeacherWrapper.eq(CeesWaiTeacher::getUserId, userId);
CeesWaiTeacher h5WaiTeacher = ceesWaiTeacherMapper.selectOne(h5WaiTeacherWrapper);
if (h5WaiTeacher != null && h5WaiTeacher.getOpenId().equals(openId)) {
// 说明已经填写过个人信息了直接放行到主页面
// 返回整个user
HashMap<String, Object> map = new HashMap<>();
map.put("user", h5WaiTeacher);
map.put("major", user.getMajorId());
map.put("status", "2"); //填写过信息
map.put("router", "/mainPage");
return Result.ok(map);
} else {
return Result.ok("/home");
}
}
return Result.error("未知错误");
}
}

View File

@ -0,0 +1,31 @@
package org.jeecg.modules.utils;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
public class HttpclientUtils {
public static JSONObject doGet(String url) throws IOException {
JSONObject jsonObject = null;
CloseableHttpClient client = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
HttpResponse response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
if (entity != null) {
String result = EntityUtils.toString(entity, "UTF-8");
jsonObject = JSONObject.parseObject(result);
}
httpGet.releaseConnection();
return jsonObject;
}
}

View File

@ -1,20 +0,0 @@
package org.jeecg.modules.utils;
import com.alibaba.fastjson.JSON;
public class Json {
/**
* 对象序列化为JSON字符串
*
* @param object
* @return
*/
public static String toJsonString(Object object) {
return JSON.toJSONString(object);
}
public static <T> T fromJson(String jsonStr, Class<T> clazz) {
return JSON.parseObject(jsonStr, clazz);
}
}

View File

@ -1,75 +0,0 @@
package org.jeecg.modules.utils;
import java.security.MessageDigest;
import java.util.Objects;
/**
* MD5加密工具类
*/
public class MD5Util {
private static final String DEFAULT_MD_5_SALT = "fjdsl321312kf349832&*^*903294[JNLIUIK]%fsdjfkl";//加盐md5盐值
/**
* 获得字符串的md5值
*
* @return md5加密后的字符串
*/
public static String getMd5(String s) {
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
byte[] btInput = s.getBytes();
// 获得MD5摘要算法的 MessageDigest 对象
MessageDigest mdInst = MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
mdInst.update(btInput);
// 获得密文
byte[] md = mdInst.digest();
// 把密文转换成十六进制的字符串形式
int j = md.length;
char[] str = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 校验字符串的md5值
*
* @param str 目标字符串
* @param md5 基准md5
* @return 校验结果
*/
public static boolean checkMd5(String str, String md5) {
return Objects.requireNonNull(getMd5(str)).equalsIgnoreCase(md5);
}
/**
* 获得加盐md5算法过程是原字符串md5后连接加盐字符串后再进行md5
*
* @param str 待加密的字符串
* @param salt
* @return 加盐md5
*/
public static String getMd5AndSalt(String str, String salt) {
return getMd5(Objects.requireNonNull(getMd5(str)).concat(salt));
}
/**
* 获得加盐md5算法过程是原字符串md5后连接加盐字符串后再进行md5
* 使用默认盐值
*
* @param str 待加密的字符串
* @return 加盐md5
*/
public static String getMd5AndSalt(String str) {
return getMd5(Objects.requireNonNull(getMd5(str)).concat(DEFAULT_MD_5_SALT));
}
}

View File

@ -0,0 +1,107 @@
package org.jeecg.modules.utils;
import java.lang.reflect.Field;
import java.util.*;
public class MapUtils {
/**
* Map转换为 Entity
*
* @param params 包含参数的Map
* @param t 需要赋值的实体
* @param <T> 类型
*/
public static <T> T mapToEntity(Map<String, Object> params, T t) {
if (null == params) {
return t;
}
Class<?> clazz = t.getClass();
Field[] declaredFields = clazz.getDeclaredFields();
try {
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
String name = declaredField.getName();
if (null != params.get(name)) {
declaredField.set(t, params.get(name));
}
}
} catch (Exception e) {
throw new RuntimeException("属性设置失败!");
}
return t;
}
/**
* 将对象转换为HashMap
*
* @param t 转换为Map的对象
* @param <T> 转换为Map的类
* @return Map
*/
public static <T> Map<String, Object> entityToMap(T t) {
Class<?> clazz = t.getClass();
List<Field> allField = getAllField(clazz);
Map<String, Object> hashMap = new LinkedHashMap<>(allField.size());
try {
for (Field declaredField : allField) {
declaredField.setAccessible(true);
Object o = declaredField.get(t);
if (null != o) {
hashMap.put(declaredField.getName(), o);
}
}
} catch (Exception e) {
throw new RuntimeException("属性获取失败!");
}
return hashMap;
}
/**
* 获取所有属性
*
* @param clazz class
* @param <T> 泛型
* @return List<Field>
*/
public static <T> List<Field> getAllField(Class<T> clazz) {
List<Field> fields = new ArrayList<>();
Class<?> superClazz = clazz;
while (null != superClazz) {
fields.addAll(Arrays.asList(superClazz.getDeclaredFields()));
superClazz = superClazz.getSuperclass();
}
return fields;
}
/**
* 将Map参数转换为字符串
*
* @param map
* @return
*/
public static String mapToString(Map<String, Object> map) {
StringBuffer sb = new StringBuffer();
map.forEach((key, value) -> {
sb.append(key).append("=").append(value.toString()).append("&");
});
String str = sb.toString();
str = str.substring(0, str.length() - 1);
return str;
}
/**
* 将Bean对象转换Url请求的字符串
*
* @param t
* @param <T>
* @return
*/
public static <T> String getUrlByBean(T t) {
String pre = "?";
Map<String, Object> map = entityToMap(t);
return pre + mapToString(map);
}
}

View File

@ -1,35 +0,0 @@
package org.jeecg.modules.utils;
import java.security.MessageDigest;
/**
* SHA1加密工具类
*/
public class SHA1Util {
public static String sha1(String s) {
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
byte[] btInput = s.getBytes();
// 获得SHA1摘要算法的 MessageDigest 对象
MessageDigest mdInst = MessageDigest.getInstance("sha-1");
// 使用指定的字节更新摘要
mdInst.update(btInput);
// 获得密文
byte[] md = mdInst.digest();
// 把密文转换成十六进制的字符串形式
int j = md.length;
char[] str = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -320,6 +320,3 @@ justauth:
type: default
prefix: 'demo::'
timeout: 1h
wechat:
appId:wx604b36a6bc00d376;
secret:f763076bef56be2c620f65a43827550e

View File

@ -3,3 +3,12 @@ spring:
name: jeecg-system
profiles:
active: '@profile.name@'
wx:
# 来源于测试平台
appid: wx2b5899dac09216d4
secret: 8bcf767da0755534f64dcf1aecfa44e2
apiUrl: https://api.weixin.qq.com/
openApiUrl: https://open.weixin.qq.com/
# authRedirectUri: http://192.168.76.1:9999/home
authRedirectUri: http://www.ceesh5.hrbnu.club/home

View File

@ -77,7 +77,7 @@
<logback.version>1.2.9</logback.version>
<!-- seata -->
<seata.version>1.5.2</seata.version>
<weixin-java.version>4.5.6.B</weixin-java.version>
<weixin-java.version>4.5.0</weixin-java.version>
</properties>
<modules>