Initial commit

This commit is contained in:
Yo Vinchen 2023-06-25 22:02:49 +08:00
parent d357b2b309
commit fed00a2a9a
13 changed files with 448 additions and 8 deletions

View File

@ -17,7 +17,7 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@MapperScan(basePackages = {"com.atguigu.auth.mapper","com.atguigu.process.mapper"})
@MapperScan(basePackages = {"com.atguigu.auth.mapper","com.atguigu.process.mapper","com.atguigu.wechat.mapper"})
public class MybatisPlusConfig {
/**

View File

@ -88,6 +88,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/favicon.ico", "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/doc.html");
web.ignoring().antMatchers("/admin/modeler/**", "/diagram-viewer/**", "/editor-app/**", "/*.html",
"/admin/processImage/**",
"/admin/wechat/authorize", "/admin/wechat/userInfo", "/admin/wechat/bindPhone",
"/favicon.ico", "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/doc.html");
}
}

View File

@ -25,7 +25,11 @@
<artifactId>spring-security</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@ -0,0 +1,93 @@
package com.atguigu.process.controller.api;
import com.alibaba.fastjson.JSON;
import com.atguigu.auth.service.SysUserService;
import com.atguigu.common.jwt.JwtHelper;
import com.atguigu.common.result.Result;
import com.atguigu.model.system.SysUser;
import com.atguigu.vo.wechat.BindPhoneVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.mp.api.WxMpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
/**
* @author YoVinchen
* @date 2023/6/25 下午 9:16
*/
@Controller
@RequestMapping("/admin/wechat")
@CrossOrigin
@Slf4j
public class WechatController {
@Resource
private SysUserService sysUserService;
@Autowired
private WxMpService wxMpService;
@Value("${wechat.userInfoUrl}")
private String userInfoUrl;
@GetMapping("/authorize")
public String authorize(@RequestParam("returnUrl") String returnUrl, HttpServletRequest request) {
//由于授权回调成功后要返回原地址路径原地址路径带#当前returnUrl获取带#的url获取不全因此前端把#号替换为guiguoa这里要还原一下
String redirectURL = wxMpService.getOAuth2Service().buildAuthorizationUrl(userInfoUrl, WxConsts.OAuth2Scope.SNSAPI_USERINFO, URLEncoder.encode(returnUrl.replace("guiguoa", "#")));
log.info("【微信网页授权】获取code,redirectURL={}", redirectURL);
return "redirect:" + redirectURL;
}
@GetMapping("/userInfo")
public String userInfo(@RequestParam("code") String code, @RequestParam("state") String returnUrl) throws Exception {
log.info("【微信网页授权】code={}", code);
log.info("【微信网页授权】state={}", returnUrl);
WxOAuth2AccessToken accessToken = wxMpService.getOAuth2Service().getAccessToken(code);
String openId = accessToken.getOpenId();
log.info("【微信网页授权】openId={}", openId);
WxOAuth2UserInfo wxMpUser = wxMpService.getOAuth2Service().getUserInfo(accessToken, null);
log.info("【微信网页授权】wxMpUser={}", JSON.toJSONString(wxMpUser));
SysUser sysUser = sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getOpenId, openId));
String token = "";
//null != sysUser 说明已经绑定反之为建立账号绑定去页面建立账号绑定
if (null != sysUser) {
token = JwtHelper.createToken(sysUser.getId(), sysUser.getUsername());
}
if (returnUrl.indexOf("?") == -1) {
return "redirect:" + returnUrl + "?token=" + token + "&openId=" + openId;
} else {
return "redirect:" + returnUrl + "&token=" + token + "&openId=" + openId;
}
}
@ApiOperation(value = "微信账号绑定手机")
@PostMapping("bindPhone")
@ResponseBody
public Result bindPhone(@RequestBody BindPhoneVo bindPhoneVo) {
SysUser sysUser = sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhone, bindPhoneVo.getPhone()));
if (null != sysUser) {
sysUser.setOpenId(bindPhoneVo.getOpenId());
sysUserService.updateById(sysUser);
String token = JwtHelper.createToken(sysUser.getId(), sysUser.getUsername());
return Result.ok(token);
} else {
return Result.fail("手机号码不存在,绑定失败");
}
}
}

View File

@ -0,0 +1,27 @@
package com.atguigu.process.service;
/**
* @author YoVinchen
* @date 2023/6/25 下午 9:41
*/
public interface MessageService {
/**
* 推送待审批人员
*
* @param processId
* @param userId
* @param taskId
*/
void pushPendingMessage(Long processId, Long userId, String taskId);
/**
* 审批后推送提交审批人员
*
* @param processId
* @param userId
* @param status
*/
void pushProcessedMessage(Long processId, Long userId, Integer status);
}

View File

@ -0,0 +1,106 @@
package com.atguigu.process.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.auth.service.SysUserService;
import com.atguigu.model.process.Process;
import com.atguigu.model.process.ProcessTemplate;
import com.atguigu.model.system.SysUser;
import com.atguigu.process.service.MessageService;
import com.atguigu.process.service.OaProcessService;
import com.atguigu.process.service.OaProcessTemplateService;
import com.atguigu.security.custom.LoginUserInfoHelper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.Map;
/**
* @author YoVinchen
* @date 2023/6/25 下午 9:41
*/
@Service
@Slf4j
public class MessageServiceImpl implements MessageService {
@Autowired
private OaProcessService oaProcessService;
@Autowired
private OaProcessTemplateService oaProcessTemplateService;
@Autowired
private SysUserService sysUserService;
@Autowired
private WxMpService wxMpService;
@SneakyThrows
@Override
public void pushPendingMessage(Long processId, Long userId, String taskId) {
Process process = oaProcessService.getById(processId);
ProcessTemplate processTemplate = oaProcessTemplateService.getById(process.getProcessTemplateId());
SysUser sysUser = sysUserService.getById(userId);
SysUser submitSysUser = sysUserService.getById(process.getUserId());
String openid = sysUser.getOpenId();
//方便测试给默认值开发者本人的openId
if (StringUtils.isEmpty(openid)) {
openid = "omwf25izKON9dktgoy0dogqvnGhk";
}
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder().toUser(openid)//要推送的用户openid
.templateId("KvOVeW7jz4-DZgQ_WuXjMZO5I4pPA7L7fflVNwC_ZQg")//模板id
.url(" http://hhdxwback.vipgz1.91tunnel.com/#/show/" + processId + "/" + taskId)//点击模板消息要访问的网址
.build();
JSONObject jsonObject = JSON.parseObject(process.getFormValues());
JSONObject formShowData = jsonObject.getJSONObject("formShowData");
StringBuffer content = new StringBuffer();
for (Map.Entry entry : formShowData.entrySet()) {
content.append(entry.getKey()).append("").append(entry.getValue()).append("\n ");
}
templateMessage.addData(new WxMpTemplateData("first", submitSysUser.getName() + "提交了" + processTemplate.getName() + "审批申请,请注意查看。", "#272727"));
templateMessage.addData(new WxMpTemplateData("keyword1", process.getProcessCode(), "#272727"));
templateMessage.addData(new WxMpTemplateData("keyword2", new DateTime(process.getCreateTime()).toString("yyyy-MM-dd HH:mm:ss"), "#272727"));
templateMessage.addData(new WxMpTemplateData("content", content.toString(), "#272727"));
String msg = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
log.info("推送消息返回:{}", msg);
}
@SneakyThrows
@Override
public void pushProcessedMessage(Long processId, Long userId, Integer status) {
Process process = oaProcessService.getById(processId);
ProcessTemplate processTemplate = oaProcessTemplateService.getById(process.getProcessTemplateId());
SysUser sysUser = sysUserService.getById(userId);
SysUser currentSysUser = sysUserService.getById(LoginUserInfoHelper.getUserId());
String openid = sysUser.getOpenId();
if (StringUtils.isEmpty(openid)) {
openid = "omwf25izKON9dktgoy0dogqvnGhk";
}
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder().toUser(openid)//要推送的用户openid
.templateId("I0kVeto7T0WIDP6tyoHh-hx83wa9_pe7Nx9eT93-6sc")//模板id
.url("http://oa.atguigu.cn/#/show/" + processId + "/0")//点击模板消息要访问的网址
.build();
JSONObject jsonObject = JSON.parseObject(process.getFormValues());
JSONObject formShowData = jsonObject.getJSONObject("formShowData");
StringBuffer content = new StringBuffer();
for (Map.Entry entry : formShowData.entrySet()) {
content.append(entry.getKey()).append("").append(entry.getValue()).append("\n ");
}
templateMessage.addData(new WxMpTemplateData("first", "你发起的" + processTemplate.getName() + "审批申请已经被处理了,请注意查看。", "#272727"));
templateMessage.addData(new WxMpTemplateData("keyword1", process.getProcessCode(), "#272727"));
templateMessage.addData(new WxMpTemplateData("keyword2", new DateTime(process.getCreateTime()).toString("yyyy-MM-dd HH:mm:ss"), "#272727"));
templateMessage.addData(new WxMpTemplateData("keyword3", currentSysUser.getName(), "#272727"));
templateMessage.addData(new WxMpTemplateData("keyword4", status == 1 ? "审批通过" : "审批拒绝", status == 1 ? "#009966" : "#FF0033"));
templateMessage.addData(new WxMpTemplateData("content", content.toString(), "#272727"));
String msg = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
log.info("推送消息返回:{}", msg);
}
}

View File

@ -8,6 +8,7 @@ import com.atguigu.model.process.ProcessRecord;
import com.atguigu.model.process.ProcessTemplate;
import com.atguigu.model.system.SysUser;
import com.atguigu.process.mapper.OaProcessMapper;
import com.atguigu.process.service.MessageService;
import com.atguigu.process.service.OaProcessRecordService;
import com.atguigu.process.service.OaProcessService;
import com.atguigu.process.service.OaProcessTemplateService;
@ -80,6 +81,8 @@ public class OaProcessServiceImpl extends ServiceImpl<OaProcessMapper, Process>
@Autowired
private HistoryService historyService;
@Autowired
private MessageService messageService;
/**
* 获取分页列表
@ -190,7 +193,8 @@ public class OaProcessServiceImpl extends ServiceImpl<OaProcessMapper, Process>
String name = user.getName();
nameList.add(name);
// TODO 6 推送消息
// 推送消息
messageService.pushPendingMessage(process.getId(), user.getId(), task.getId());
}
process.setProcessInstanceId(processInstance.getId());
process.setDescription("等待" + StringUtils.join(nameList.toArray(), ",") + "审批");
@ -311,7 +315,6 @@ public class OaProcessServiceImpl extends ServiceImpl<OaProcessMapper, Process>
SysUser sysUser = sysUserService.getUserByUsername(assignee);
assignList.add(sysUser.getName());
//TODO 公众号消息推送
}
//更新process流程信息
process.setDescription("等待" + StringUtils.join(assignList.toArray(), ",") + "审批");

View File

@ -0,0 +1,35 @@
package com.atguigu.wechat.config;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* @author YoVinchen
* @date 2023/6/25 下午 7:24
*/
@Component
public class WeChatMpConfig {
@Autowired
private WechatAccountConfig wechatAccountConfig;
@Bean
public WxMpService wxMpService() {
WxMpService wxMpService = new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(wxMpConfigStorage());
return wxMpService;
}
@Bean
public WxMpConfigStorage wxMpConfigStorage() {
WxMpDefaultConfigImpl wxMpConfigStorage = new WxMpDefaultConfigImpl();
wxMpConfigStorage.setAppId(wechatAccountConfig.getMpAppId());
wxMpConfigStorage.setSecret(wechatAccountConfig.getMpAppSecret());
return wxMpConfigStorage;
}
}

View File

@ -0,0 +1,20 @@
package com.atguigu.wechat.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author YoVinchen
* @date 2023/6/25 下午 7:22
*/
@Data
@Component
@ConfigurationProperties(prefix = "wechat")
public class WechatAccountConfig {
private String mpAppId;
private String mpAppSecret;
}

View File

@ -1,9 +1,15 @@
package com.atguigu.wechat.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.atguigu.common.result.Result;
import com.atguigu.vo.wechat.MenuVo;
import com.atguigu.wechat.service.MenuService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
@ -14,8 +20,32 @@ import org.springframework.web.bind.annotation.RestController;
* @since 2023-06-25
*/
@RestController
@RequestMapping("/wechat/menu")
@RequestMapping("/admin/wechat/menu")
@Slf4j
@CrossOrigin
public class MenuController {
@Autowired
private MenuService menuService;
@ApiOperation(value = "删除菜单")
@DeleteMapping("removeMenu")
public Result removeMenu() {
menuService.removeMenu();
return Result.ok();
}
@ApiOperation(value = "同步菜单")
@GetMapping("syncMenu")
public Result createMenu() {
menuService.syncMenu();
return Result.ok();
}
@ApiOperation(value = "获取全部菜单")
@GetMapping("findMenuInfo")
public Result findMenuInfo() {
List<MenuVo> menuList = menuService.findMenuInfo();
return Result.ok(menuList);
}
}

View File

@ -1,8 +1,11 @@
package com.atguigu.wechat.service;
import com.atguigu.model.wechat.Menu;
import com.atguigu.vo.wechat.MenuVo;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* <p>
* 菜单 服务类
@ -13,4 +16,12 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface MenuService extends IService<Menu> {
//获取全部菜单
List<MenuVo> findMenuInfo();
//同步菜单
void syncMenu();
//删除菜单
void removeMenu();
}

View File

@ -1,10 +1,22 @@
package com.atguigu.wechat.service.impl;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.atguigu.model.wechat.Menu;
import com.atguigu.vo.wechat.MenuVo;
import com.atguigu.wechat.mapper.MenuMapper;
import com.atguigu.wechat.service.MenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
@ -16,5 +28,96 @@ import org.springframework.stereotype.Service;
*/
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
@Autowired
private WxMpService wxMpService;
//获取全部菜单
@Override
public List<MenuVo> findMenuInfo() {
List<MenuVo> list = new ArrayList<>();
//1 查询所有菜单list集合
List<Menu> menuList = baseMapper.selectList(null);
//2 查询所有一级菜单 parent_id=0返回一级菜单list集合
List<Menu> oneMenuList = menuList.stream().filter(menu -> menu.getParentId().longValue() == 0).collect(Collectors.toList());
//3 一级菜单list集合遍历得到每个一级菜单
for (Menu oneMenu : oneMenuList) {
//一级菜单Menu --- MenuVo
MenuVo oneMenuVo = new MenuVo();
BeanUtils.copyProperties(oneMenu, oneMenuVo);
//4 获取每个一级菜单里面所有二级菜单 id parent_id比较
//一级菜单id 其他菜单parent_id
List<Menu> twoMenuList = menuList.stream().filter(menu -> menu.getParentId().longValue() == oneMenu.getId()).collect(Collectors.toList());
//5 把一级菜单里面所有二级菜单获取到封装一级菜单children集合里面
//List<Menu> -- List<MenuVo>
List<MenuVo> children = new ArrayList<>();
for (Menu twoMenu : twoMenuList) {
MenuVo twoMenuVo = new MenuVo();
BeanUtils.copyProperties(twoMenu, twoMenuVo);
children.add(twoMenuVo);
}
oneMenuVo.setChildren(children);
//把每个封装好的一级菜单放到最终list集合
list.add(oneMenuVo);
}
return list;
}
//同步菜单
@Override
public void syncMenu() {
//1 菜单数据查询出来封装微信要求菜单格式
List<MenuVo> menuVoList = this.findMenuInfo();
//菜单
JSONArray buttonList = new JSONArray();
for (MenuVo oneMenuVo : menuVoList) {
JSONObject one = new JSONObject();
one.put("name", oneMenuVo.getName());
if (CollectionUtils.isEmpty(oneMenuVo.getChildren())) {
one.put("type", oneMenuVo.getType());
one.put("url", "http://hhdxwback.vipgz1.91tunnel.com/#" + oneMenuVo.getUrl());
} else {
JSONArray subButton = new JSONArray();
for (MenuVo twoMenuVo : oneMenuVo.getChildren()) {
JSONObject view = new JSONObject();
view.put("type", twoMenuVo.getType());
if (twoMenuVo.getType().equals("view")) {
view.put("name", twoMenuVo.getName());
//H5页面地址
view.put("url", "http://hhdxwback.vipgz1.91tunnel.com#" + twoMenuVo.getUrl());
} else {
view.put("name", twoMenuVo.getName());
view.put("key", twoMenuVo.getMeunKey());
}
subButton.add(view);
}
one.put("sub_button", subButton);
}
buttonList.add(one);
}
//菜单
JSONObject button = new JSONObject();
button.put("button", buttonList);
//2 调用工具里面的方法实现菜单推送
try {
wxMpService.getMenuService().menuCreate(button.toString());
} catch (WxErrorException e) {
throw new RuntimeException(e);
}
}
//删除菜单
@Override
public void removeMenu() {
try {
wxMpService.getMenuService().menuDelete();
} catch (WxErrorException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -46,3 +46,8 @@ spring:
history-level: full
#校验流程文件默认校验resources下的process 文件夹的流程文件
check-process-definitions: true
wechat:
mpAppId: wxb9fd95abd9f4053f
mpAppSecret: 34609f69a07dde17631c78bb912450b2
# 授权回调获取用户信息接口地址
userInfoUrl: http://hhdxw.free.idcfengye.com/admin/wechat/userInfo