From 1131c713bdbd04dbb3191e38439cd74c374f33f0 Mon Sep 17 00:00:00 2001 From: wangfukang <15630117759@163.com> Date: Tue, 7 Jan 2025 17:15:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=85=AC=E4=BC=97=E5=8F=B7?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application.yml | 48 +++- hiver-admin/test-output/test-report.html | 16 +- hiver-core/pom.xml | 6 + .../main/java/cc/hiver/core/dao/UserDao.java | 15 +- .../main/java/cc/hiver/core/entity/User.java | 14 +- .../cc/hiver/core/service/UserService.java | 35 ++- .../core/serviceimpl/UserServiceImpl.java | 197 ++++++++++----- .../controller/ShopPrintController.java | 12 +- .../shopprint/service/ShopPrintService.java | 2 + .../service/impl/ShopPrintServiceImpl.java | 96 +++++++- .../main/java/cc/hiver/core/vo/WechatVo.java | 28 +++ hiver-modules/hiver-base/pom.xml | 12 + .../controller/manage/UserController.java | 229 +++++++++++++++++- .../java/cc/hiver/base/utils/WeChatUtil.java | 40 +++ .../mall/controller/CustomerController.java | 43 +++- .../hiver/mall/controller/SaleController.java | 36 ++- .../hiver/mall/dao/mapper/CustomerMapper.java | 16 +- .../java/cc/hiver/mall/entity/Customer.java | 16 ++ .../cc/hiver/mall/pojo/dto/SaleQueryDTO.java | 3 + .../impl/PurchaseReturnServiceImpl.java | 1 + .../mall/service/mybatis/CustomerService.java | 28 ++- .../SalesAndDetailsServiceImpl.java | 12 +- .../SalesCalculateServiceImpl.java | 2 +- .../mybatis/CustomerServiceImpl.java | 40 ++- .../main/resources/mapper/CustomerMapper.xml | 55 ++++- hiver-modules/hiver-social/pom.xml | 14 ++ .../social/config/MessageRouterConfig.java | 36 +++ .../social/config/WxMpConfiguration.java | 44 ++++ .../hiver/social/config/WxMpProperties.java | 31 +++ .../social/controller/WechatController.java | 168 +++++++++++-- .../social/handler/WxServerMsgHandler.java | 67 +++++ .../interceptor/WxServerMsgInterceptor.java | 29 +++ .../cc/hiver/social/vo/WeChatServerMsgVo.java | 47 ++++ 33 files changed, 1281 insertions(+), 157 deletions(-) create mode 100644 hiver-core/src/main/java/cc/hiver/core/vo/WechatVo.java create mode 100644 hiver-modules/hiver-base/src/main/java/cc/hiver/base/utils/WeChatUtil.java create mode 100644 hiver-modules/hiver-social/src/main/java/cc/hiver/social/config/MessageRouterConfig.java create mode 100644 hiver-modules/hiver-social/src/main/java/cc/hiver/social/config/WxMpConfiguration.java create mode 100644 hiver-modules/hiver-social/src/main/java/cc/hiver/social/config/WxMpProperties.java create mode 100644 hiver-modules/hiver-social/src/main/java/cc/hiver/social/handler/WxServerMsgHandler.java create mode 100644 hiver-modules/hiver-social/src/main/java/cc/hiver/social/interceptor/WxServerMsgInterceptor.java create mode 100644 hiver-modules/hiver-social/src/main/java/cc/hiver/social/vo/WeChatServerMsgVo.java diff --git a/hiver-admin/src/main/resources/application.yml b/hiver-admin/src/main/resources/application.yml index a65c3ec8..58f6409b 100644 --- a/hiver-admin/src/main/resources/application.yml +++ b/hiver-admin/src/main/resources/application.yml @@ -65,7 +65,7 @@ spring: # 自动生成表结构 关闭设为none hibernate: ddl-auto: update - # Redis 若设有密码自行添加配置password + # Redis 若设有密码自行添加配置password redis: host: 154.8.162.157 # host: 8.140.198.243 @@ -221,9 +221,9 @@ hiver: callbackUrl: http://127.0.0.1:8888/hiver/social/weibo/callback # wechat wechat: - appId: 你的appId - appSecret: 你的appSecret - callbackUrl: http://127.0.0.1:8888/hiver/social/wechat/callback + appId: wx6d7d4fb58d1502db + appSecret: 3a2c8cd00926764bbd12fd7361e01f1d + callbackUrl: https://storage.xenjoyou.com/hiver/social/wechat/callback # 钉钉 dingding: # 扫码登录应用 @@ -241,8 +241,38 @@ app: social: # 微信小程序 wxMini: - appId: 你的appId - appSecret: 你的appSecret + appId: wx6d7d4fb58d1502db + appSecret: 3a2c8cd00926764bbd12fd7361e01f1d + auth: + token: kuaiyidian + appId: wx6d7d4fb58d1502db + appSecret: 3a2c8cd00926764bbd12fd7361e01f1d +wx: + # 消息模板ID + templateId: o9YG7vWS8It-mddU2Wnknf1jgzTqZtLeBQRLhF54SXQ + mp: + # 微信公众号的appid + appId: wx415a86fa6c2eff11 + # 信公众号的app secret + secret: b4bf01832f7a640353367d8979409900 + # 微信公众号的toke + token: kuaiyidian + # 微信公众号的EncodingAESKey + aesKey: D6VSlBgYeKRRweR2rNuNQpcrBKdVDzRMnAvMflIJ931 + config-storage: + # 配置类型: Memory(默认), Jedis, Redisson, RedisTemplate + type: RedisTemplate + # redis前缀配置: wx(默认) + key-prefix: wx + redis: + host: 154.8.162.157 +# host: 8.140.198.243 + password: reddoor168 + # 数据库索引 默认0 + database: 1 + port: 6379 + # 超时时间 Duration类型 3秒 + timeout: 3S # 需要验证码校验的接口路径 支持通配符 自动过滤拦截校验 无需开发人员再次校验 captcha: # 图片验证码验证 @@ -348,6 +378,10 @@ ignored: - /hiver/app/customer/getCustomerData - /hiver/app/supplier/getSupplierData - /hiver/app/urlMapping/redirect + # 关注微信公众号回调 + - /hiver/user/officialAccount + - /hiver/social/wechat/echo + # 临时增加 - /hiver/app/logisticsOrder/addLogisticsOrder @@ -355,6 +389,8 @@ ignored: - /hiver/app/logisticsEntruckingLog/batchAddLogisticsEntruckingLog - /hiver/purchaseOcrPicture/getLogisticsOrderOfAi - /hiver/app/product/** + - /hiver/user/login + - /hiver/app/shopprint/printImg # 限流及黑名单不拦截的路径 limitUrls: - /**/*.js diff --git a/hiver-admin/test-output/test-report.html b/hiver-admin/test-output/test-report.html index cc03918e..e1c934ee 100644 --- a/hiver-admin/test-output/test-report.html +++ b/hiver-admin/test-output/test-report.html @@ -35,7 +35,7 @@ Hiver
  • -ʮһ 27, 2024 22:06:17 +һ 07, 2025 16:21:35
  • @@ -84,7 +84,7 @@

    passTest

    -

    22:06:18 / 0.023 secs

    +

    16:21:35 / 0.016 secs

    @@ -92,9 +92,9 @@
    #test-id=1
    passTest
    -11.27.2024 22:06:18 -11.27.2024 22:06:18 -0.023 secs +01.07.2025 16:21:35 +01.07.2025 16:21:35 +0.016 secs
    @@ -104,7 +104,7 @@ Pass - 22:06:18 + 16:21:35 Test passed @@ -128,13 +128,13 @@

    Started

    -

    ʮһ 27, 2024 22:06:17

    +

    һ 07, 2025 16:21:35

    Ended

    -

    ʮһ 27, 2024 22:06:18

    +

    һ 07, 2025 16:21:35

    diff --git a/hiver-core/pom.xml b/hiver-core/pom.xml index d7e7fdb6..9bea1c3b 100644 --- a/hiver-core/pom.xml +++ b/hiver-core/pom.xml @@ -170,5 +170,11 @@ pinyin4j 2.5.0 + + com.github.binarywang + weixin-java-mp + 4.6.0 + compile + \ No newline at end of file diff --git a/hiver-core/src/main/java/cc/hiver/core/dao/UserDao.java b/hiver-core/src/main/java/cc/hiver/core/dao/UserDao.java index 45f833bb..3914bca6 100644 --- a/hiver-core/src/main/java/cc/hiver/core/dao/UserDao.java +++ b/hiver-core/src/main/java/cc/hiver/core/dao/UserDao.java @@ -85,7 +85,20 @@ public interface UserDao extends HiverBaseDao { @Query("select u from User u where u.email = ?1 and u.type like %?2% ") User findByEmailAndType(String email,String type); - @Query(value = "select s.type,t.id,t.create_by,t.create_time,t.del_flag,t.update_by,t.update_time,t.address,t.avatar,t.description,t.email,t.mobile,t.nickname,t.password,t.sex,t.status,t.username,t.department_id,t.street,t.pass_strength,t.department_title,t.birth,t.invite_code,t.client_id from t_shop_user s left join t_user t on s.user_id = t.id where s.shop_id = ?",nativeQuery = true) + @Query(value = "select s.type,t.id,t.create_by,t.create_time,t.del_flag,t.update_by,t.update_time,t.address,t.avatar,t.description,t.email,t.mobile,t.nickname,t.password,t.sex,t.status,t.username,t.department_id,t.street,t.pass_strength,t.department_title,t.birth,t.invite_code,t.client_id,t.mini_program_openid,t.unionid,t.official_account_openid,t.wechat_name from t_shop_user s left join t_user t on s.user_id = t.id where s.shop_id = ?",nativeQuery = true) List findByShopId( String shopId); + @Query("select u from User u where u.unionid = ?1 ") + User findByUnionid(String unionid); + + @Query("select u from User u where u.miniProgramOpenid = ?1 ") + User findByMiniProgramOpenid(String miniProgramOpenid); + + @Modifying + @Query("update User u set u.mobile='' where u.mobile=?1") + void setUserPhoneToNull(String userPhone); + + @Modifying + @Query("update User u set u.mobile=?1 where u.id=?2") + void updateUserPhoneById(String userPhone, String userId); } diff --git a/hiver-core/src/main/java/cc/hiver/core/entity/User.java b/hiver-core/src/main/java/cc/hiver/core/entity/User.java index cf45a31c..9bc7b817 100644 --- a/hiver-core/src/main/java/cc/hiver/core/entity/User.java +++ b/hiver-core/src/main/java/cc/hiver/core/entity/User.java @@ -20,7 +20,6 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Table; import javax.persistence.Transient; -import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import java.util.Date; @@ -122,4 +121,17 @@ public class User extends HiverBaseEntity { @Transient @ApiModelProperty(value = "是否有维护成本权限 1:是;0否") private Integer shopAdminCost; + + + @ApiModelProperty(value = "小程序id") + private String miniProgramOpenid; + + @ApiModelProperty(value = "微信平台统一id") + private String unionid; + + @ApiModelProperty(value = "公众号id") + private String officialAccountOpenid; + + @ApiModelProperty(value = "微信昵称") + private String wechatName; } diff --git a/hiver-core/src/main/java/cc/hiver/core/service/UserService.java b/hiver-core/src/main/java/cc/hiver/core/service/UserService.java index ba6fc22b..5130b68e 100644 --- a/hiver-core/src/main/java/cc/hiver/core/service/UserService.java +++ b/hiver-core/src/main/java/cc/hiver/core/service/UserService.java @@ -3,11 +3,11 @@ package cc.hiver.core.service; import cc.hiver.core.base.HiverBaseService; import cc.hiver.core.common.vo.SearchVo; import cc.hiver.core.entity.User; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.result.WxMpUser; import org.springframework.cache.annotation.CacheConfig; -import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import java.util.List; @@ -43,6 +43,15 @@ public interface UserService extends HiverBaseService { */ User findByEmail(String email); + /** + * 获取用户角色权限 + * @author 王富康 + * @date 2024/12/3 + * @param user + * @return User + */ + User userToDTO(User user); + /** * 多条件分页获取用户 * @@ -107,4 +116,26 @@ public interface UserService extends HiverBaseService { User findByUserNameAndType(String userName,String type); User findByMobileAndType(String mobile,String type); List findByShopId(String shopId); + + /** + * 公众号关注 + * @author 王富康 + * @date 2024/12/29 + */ + void subscribeWxServer(WxMpUser user); + + /** + * 取消公众号关注 + * @author 王富康 + * @date 2024/12/29 + */ + void unSubscribeWxServer(WxMpXmlMessage wxMessage); + + User findByUnionid(String unionid); + + User findByMiniProgramOpenid(String miniProgramOpenid); + + void setUserPhoneToNull(String userPhone); + + void updateUserPhoneById(String userPhone, String userId); } diff --git a/hiver-core/src/main/java/cc/hiver/core/serviceimpl/UserServiceImpl.java b/hiver-core/src/main/java/cc/hiver/core/serviceimpl/UserServiceImpl.java index 7e224c08..c9342859 100644 --- a/hiver-core/src/main/java/cc/hiver/core/serviceimpl/UserServiceImpl.java +++ b/hiver-core/src/main/java/cc/hiver/core/serviceimpl/UserServiceImpl.java @@ -1,7 +1,10 @@ package cc.hiver.core.serviceimpl; import cc.hiver.core.common.constant.CommonConstant; +import cc.hiver.core.common.constant.UserConstant; +import cc.hiver.core.common.utils.PageUtil; import cc.hiver.core.common.utils.SecurityUtil; +import cc.hiver.core.common.vo.PageVo; import cc.hiver.core.common.vo.SearchVo; import cc.hiver.core.dao.UserDao; import cc.hiver.core.dao.mapper.PermissionMapper; @@ -9,12 +12,17 @@ import cc.hiver.core.dao.mapper.UserRoleMapper; import cc.hiver.core.entity.Permission; import cc.hiver.core.entity.Role; import cc.hiver.core.entity.User; +import cc.hiver.core.entity.UserRole; +import cc.hiver.core.service.RoleService; +import cc.hiver.core.service.UserRoleService; import cc.hiver.core.service.UserService; import cc.hiver.core.vo.PermissionDTO; import cc.hiver.core.vo.RoleDTO; import cn.hutool.core.date.DateUtil; -import cn.hutool.core.util.StrUtil; +import cn.hutool.core.text.CharSequenceUtil; import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.result.WxMpUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -24,9 +32,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.persistence.criteria.*; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; /** @@ -50,6 +56,12 @@ public class UserServiceImpl implements UserService { @Autowired private SecurityUtil securityUtil; + @Autowired + private UserRoleService userRoleService; + + @Autowired + private RoleService roleService; + @Override public UserDao getRepository() { return userDao; @@ -57,35 +69,36 @@ public class UserServiceImpl implements UserService { @Override public User findByUsername(String username) { - User user = userDao.findByUsername(username); + final User user = userDao.findByUsername(username); return userToDTO(user); } @Override public User findByMobile(String mobile) { - User user = userDao.findByMobile(mobile); + final User user = userDao.findByMobile(mobile); return userToDTO(user); } @Override public User findByEmail(String email) { - User user = userDao.findByEmail(email); + final User user = userDao.findByEmail(email); return userToDTO(user); } + @Override public User userToDTO(User user) { if (user == null) { return null; } // 关联角色 - List roleList = userRoleMapper.findByUserId(user.getId()); - List roleDTOList = roleList.stream().map(e -> { + final List roleList = userRoleMapper.findByUserId(user.getId()); + final List roleDTOList = roleList.stream().map(e -> { return new RoleDTO().setId(e.getId()).setName(e.getName()); }).collect(Collectors.toList()); user.setRoles(roleDTOList); // 关联权限菜单 - List permissionList = permissionMapper.findByUserId(user.getId()); - List permissionDTOList = permissionList.stream() + final List permissionList = permissionMapper.findByUserId(user.getId()); + final List permissionDTOList = permissionList.stream() .filter(e -> CommonConstant.PERMISSION_OPERATION.equals(e.getType())) .map(e -> { return new PermissionDTO().setTitle(e.getTitle()).setPath(e.getPath()); @@ -100,43 +113,43 @@ public class UserServiceImpl implements UserService { @Nullable @Override public Predicate toPredicate(Root root, CriteriaQuery cq, CriteriaBuilder cb) { - Path idField = root.get("id"); - Path usernameField = root.get("username"); - Path nicknameField = root.get("nickname"); - Path mobileField = root.get("mobile"); - Path emailField = root.get("email"); - Path departmentIdField = root.get("departmentId"); - Path sexField = root.get("sex"); - Path statusField = root.get("status"); - Path createTimeField = root.get("createTime"); - - List list = new ArrayList<>(); - - if (StrUtil.isNotBlank(user.getId())) { + final Path idField = root.get("id"); + final Path usernameField = root.get("username"); + final Path nicknameField = root.get("nickname"); + final Path mobileField = root.get("mobile"); + final Path emailField = root.get("email"); + final Path departmentIdField = root.get("departmentId"); + final Path sexField = root.get("sex"); + final Path statusField = root.get("status"); + final Path createTimeField = root.get("createTime"); + + final List list = new ArrayList<>(); + + if (CharSequenceUtil.isNotBlank(user.getId())) { list.add(cb.equal(idField, user.getId())); } // 模糊搜素 - if (StrUtil.isNotBlank(user.getUsername())) { + if (CharSequenceUtil.isNotBlank(user.getUsername())) { list.add(cb.like(usernameField, '%' + user.getUsername() + '%')); } - if (StrUtil.isNotBlank(user.getNickname())) { + if (CharSequenceUtil.isNotBlank(user.getNickname())) { list.add(cb.like(nicknameField, '%' + user.getNickname() + '%')); } - if (StrUtil.isNotBlank(user.getMobile())) { + if (CharSequenceUtil.isNotBlank(user.getMobile())) { list.add(cb.like(mobileField, '%' + user.getMobile() + '%')); } - if (StrUtil.isNotBlank(user.getEmail())) { + if (CharSequenceUtil.isNotBlank(user.getEmail())) { list.add(cb.like(emailField, '%' + user.getEmail() + '%')); } // 部门 - if (StrUtil.isNotBlank(user.getDepartmentId())) { + if (CharSequenceUtil.isNotBlank(user.getDepartmentId())) { list.add(cb.equal(departmentIdField, user.getDepartmentId())); } // 性别 - if (StrUtil.isNotBlank(user.getSex())) { + if (CharSequenceUtil.isNotBlank(user.getSex())) { list.add(cb.equal(sexField, user.getSex())); } // 状态 @@ -144,19 +157,19 @@ public class UserServiceImpl implements UserService { list.add(cb.equal(statusField, user.getStatus())); } // 创建时间 - if (StrUtil.isNotBlank(searchVo.getStartDate()) && StrUtil.isNotBlank(searchVo.getEndDate())) { - Date start = DateUtil.parse(searchVo.getStartDate()); - Date end = DateUtil.parse(searchVo.getEndDate()); + if (CharSequenceUtil.isNotBlank(searchVo.getStartDate()) && CharSequenceUtil.isNotBlank(searchVo.getEndDate())) { + final Date start = DateUtil.parse(searchVo.getStartDate()); + final Date end = DateUtil.parse(searchVo.getEndDate()); list.add(cb.between(createTimeField, start, DateUtil.endOfDay(end))); } // 数据权限 - List depIds = securityUtil.getDeparmentIds(); + final List depIds = securityUtil.getDeparmentIds(); if (depIds != null && depIds.size() > 0) { list.add(departmentIdField.in(depIds)); } - Predicate[] arr = new Predicate[list.size()]; + final Predicate[] arr = new Predicate[list.size()]; cq.where(list.toArray(arr)); return null; } @@ -169,33 +182,33 @@ public class UserServiceImpl implements UserService { @Nullable @Override public Predicate toPredicate(Root root, CriteriaQuery cq, CriteriaBuilder cb) { - Path usernameField = root.get("username"); - Path nicknameField = root.get("nickname"); - Path mobileField = root.get("mobile"); - Path sexField = root.get("sex"); - Path statusField = root.get("status"); - Path createTimeField = root.get("createTime"); - Path inviteCodeField = root.get("inviteCode"); + final Path usernameField = root.get("username"); + final Path nicknameField = root.get("nickname"); + final Path mobileField = root.get("mobile"); + final Path sexField = root.get("sex"); + final Path statusField = root.get("status"); + final Path createTimeField = root.get("createTime"); + final Path inviteCodeField = root.get("inviteCode"); - List list = new ArrayList<>(); + final List list = new ArrayList<>(); // 模糊搜素 - if (StrUtil.isNotBlank(user.getUsername())) { + if (CharSequenceUtil.isNotBlank(user.getUsername())) { list.add(cb.like(usernameField, '%' + user.getUsername() + '%')); } - if (StrUtil.isNotBlank(user.getNickname())) { + if (CharSequenceUtil.isNotBlank(user.getNickname())) { list.add(cb.like(nicknameField, '%' + user.getNickname() + '%')); } - if (StrUtil.isNotBlank(user.getMobile())) { + if (CharSequenceUtil.isNotBlank(user.getMobile())) { list.add(cb.like(mobileField, '%' + user.getMobile() + '%')); } // 性别 - if (StrUtil.isNotBlank(user.getSex())) { + if (CharSequenceUtil.isNotBlank(user.getSex())) { list.add(cb.equal(sexField, user.getSex())); } // 邀请人 - if (StrUtil.isNotBlank(user.getInviteCode())) { + if (CharSequenceUtil.isNotBlank(user.getInviteCode())) { list.add(cb.equal(inviteCodeField, user.getInviteCode())); } // 状态 @@ -203,13 +216,13 @@ public class UserServiceImpl implements UserService { list.add(cb.equal(statusField, user.getStatus())); } // 创建时间 - if (StrUtil.isNotBlank(searchVo.getStartDate()) && StrUtil.isNotBlank(searchVo.getEndDate())) { - Date start = DateUtil.parse(searchVo.getStartDate()); - Date end = DateUtil.parse(searchVo.getEndDate()); + if (CharSequenceUtil.isNotBlank(searchVo.getStartDate()) && CharSequenceUtil.isNotBlank(searchVo.getEndDate())) { + final Date start = DateUtil.parse(searchVo.getStartDate()); + final Date end = DateUtil.parse(searchVo.getEndDate()); list.add(cb.between(createTimeField, start, DateUtil.endOfDay(end))); } - Predicate[] arr = new Predicate[list.size()]; + final Predicate[] arr = new Predicate[list.size()]; cq.where(list.toArray(arr)); return null; } @@ -241,16 +254,86 @@ public class UserServiceImpl implements UserService { return userDao.findByRoleName(roleName); } - public User findByUserNameAndType(String userName,String type){ - User user = userDao.findByUserNameAndType(userName,type); + @Override + public User findByUserNameAndType(String userName, String type) { + final User user = userDao.findByUserNameAndType(userName, type); return userToDTO(user); } - public User findByMobileAndType(String mobile,String type){ - User user = userDao.findByMobileAndType(mobile,type); + + @Override + public User findByMobileAndType(String mobile, String type) { + final User user = userDao.findByMobileAndType(mobile, type); return userToDTO(user); } - public List findByShopId(String shopId){ + @Override + public List findByShopId(String shopId) { return userDao.findByShopId(shopId); } + + @Override + public void subscribeWxServer(WxMpUser user) { + // 判断是否绑定用户 + final String unionid = user.getUnionId(); + final String openid = user.getOpenId(); + User wechatUser = findByUnionid(unionid); + final Map resultMap = new HashMap<>(); + if (wechatUser != null) { + wechatUser.setOfficialAccountOpenid(openid); + } else { + try { + // 新增用户信息 + wechatUser = new User(); + wechatUser.setUnionid(unionid); + wechatUser.setOfficialAccountOpenid(openid); + wechatUser.setStatus(UserConstant.USER_STATUS_NORMAL); + wechatUser = save(wechatUser); + // 设置用户角色 + final UserRole userRole = new UserRole(); + final PageVo pageVo = new PageVo(); + pageVo.setPageNumber(1); + pageVo.setPageSize(1); + final Page roleCustomer = roleService.findByCondition("ROLE_CUSTOMER", PageUtil.initPage(pageVo)); + final Role role = roleCustomer.getContent().get(0); + //客户角色 + userRole.setRoleId(role.getId()); + userRole.setRoleName("客户"); + userRole.setUserId(wechatUser.getId()); + userRoleService.save(userRole); + // 更新客户信息,绑定登录用户 + // customerService.updateUserId(wechatVo.getCustomId(),wechatUser.getId()); + // 返回当前登录人的信息 + resultMap.put("msg", "新增用户信息,并绑定成功!"); + // resultMap.put("customId", wechatVo.getCustomId()); + } catch (Exception e) { + log.error("公众号关注出现错误,请查看!" + e.getMessage(), e); + } + } + save(wechatUser); + } + + @Override + public void unSubscribeWxServer(WxMpXmlMessage wxMessage) { + + } + + @Override + public User findByUnionid(String unionid) { + return userDao.findByUnionid(unionid); + } + + @Override + public User findByMiniProgramOpenid(String miniProgramOpenid) { + return userDao.findByMiniProgramOpenid(miniProgramOpenid); + } + + @Override + public void setUserPhoneToNull(String userPhone) { + userDao.setUserPhoneToNull(userPhone); + } + + @Override + public void updateUserPhoneById(String userPhone, String userId) { + userDao.updateUserPhoneById(userPhone, userId); + } } diff --git a/hiver-core/src/main/java/cc/hiver/core/shopprint/controller/ShopPrintController.java b/hiver-core/src/main/java/cc/hiver/core/shopprint/controller/ShopPrintController.java index 02978caa..3fdfe669 100644 --- a/hiver-core/src/main/java/cc/hiver/core/shopprint/controller/ShopPrintController.java +++ b/hiver-core/src/main/java/cc/hiver/core/shopprint/controller/ShopPrintController.java @@ -2,13 +2,9 @@ package cc.hiver.core.shopprint.controller; import cc.hiver.core.common.utils.ResultUtil; import cc.hiver.core.common.vo.Result; -import cc.hiver.core.logisticsroute.entity.LogisticsRoute; -import cc.hiver.core.logisticsroute.service.LogisticsRouteService; -import cc.hiver.core.logisticsroute.vo.LogisticsRouteQueryVo; import cc.hiver.core.shopprint.entity.ShopPrint; import cc.hiver.core.shopprint.service.ShopPrintService; import cc.hiver.core.shopprint.vo.ShopPrintQueryVo; -import com.baomidou.mybatisplus.core.metadata.IPage; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; @@ -88,4 +84,12 @@ public class ShopPrintController { final List result = shopPrintService.getShopPrintList(shopPrintQueryVo); return new ResultUtil>().setData(result); } + + // 打印图片 + @RequestMapping(value = "/printImg", method = RequestMethod.POST) + @ApiOperation(value = "打印图片") + public Result printImg(String imgPath) { + final String result = shopPrintService.printImg(imgPath); + return new ResultUtil().setData(result); + } } diff --git a/hiver-core/src/main/java/cc/hiver/core/shopprint/service/ShopPrintService.java b/hiver-core/src/main/java/cc/hiver/core/shopprint/service/ShopPrintService.java index b5e61d94..c8817b0a 100644 --- a/hiver-core/src/main/java/cc/hiver/core/shopprint/service/ShopPrintService.java +++ b/hiver-core/src/main/java/cc/hiver/core/shopprint/service/ShopPrintService.java @@ -10,4 +10,6 @@ public interface ShopPrintService extends IService { List getShopPrintList(ShopPrintQueryVo shopPrintQueryVo); + + String printImg(String imgPath); } diff --git a/hiver-core/src/main/java/cc/hiver/core/shopprint/service/impl/ShopPrintServiceImpl.java b/hiver-core/src/main/java/cc/hiver/core/shopprint/service/impl/ShopPrintServiceImpl.java index d8bbf00e..318b3afb 100644 --- a/hiver-core/src/main/java/cc/hiver/core/shopprint/service/impl/ShopPrintServiceImpl.java +++ b/hiver-core/src/main/java/cc/hiver/core/shopprint/service/impl/ShopPrintServiceImpl.java @@ -1,19 +1,17 @@ package cc.hiver.core.shopprint.service.impl; -import cc.hiver.core.logisticsroute.mapper.LogisticsRouteMapper; -import cc.hiver.core.logisticsroute.service.LogisticsRouteService; -import cc.hiver.core.logisticsuser.entity.LogisticsUser; -import cc.hiver.core.logisticsuser.mapper.LogisticsUserMapper; -import cc.hiver.core.logisticsuser.service.LogisticsUserService; import cc.hiver.core.shopprint.entity.ShopPrint; import cc.hiver.core.shopprint.mapper.ShopPrintMapper; import cc.hiver.core.shopprint.service.ShopPrintService; import cc.hiver.core.shopprint.vo.ShopPrintQueryVo; -import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.net.URL; import java.util.List; /** @@ -22,6 +20,7 @@ import java.util.List; * @Date: 2024/10/22 22:01 * @Description: */ +@Slf4j @Service public class ShopPrintServiceImpl extends ServiceImpl implements ShopPrintService { @@ -29,8 +28,91 @@ public class ShopPrintServiceImpl extends ServiceImpl getShopPrintList(ShopPrintQueryVo shopPrintQueryVo){ + public List getShopPrintList(ShopPrintQueryVo shopPrintQueryVo) { return shopPrintMapper.getShopPrintList(shopPrintQueryVo); } + @Override + public String printImg(String imgPath) { + final URL url; + BufferedImage image = null; + try { + url = new URL(imgPath); + image = ImageIO.read(url); + } catch (Exception e) { + log.error("读取文件错误: " + e.getMessage()); + } + if (image != null) { + return drawGraphic(0,0, image); + } + return "未读取到图片信息!"; + } + + public static String drawGraphic(int start_x, int start_y, BufferedImage image) { + int width = image.getWidth(); + int height = image.getHeight(); + + int col = (width - 1) / 8 + 1; + + String str = ""; + byte[] arrayOfByte = new byte[width * height]; + + int h = 0; + //int b1 = 0; + int arrindex = 0; + //int m = 0; + + + while (h < height) { + for (int w = 0; w < width; w++) { + arrindex = h * col + w / 8; + System.out.println("w:" + w + ", h:" + h); + if ((image.getRGB(w, h) & 0xFFFFFF) < 3092271) { + int n = arrindex; + byte[] arrayOfByte1 = arrayOfByte; + + arrayOfByte1[n] = (byte) (arrayOfByte1[n] | 128 >> w % 8); + } else { + int n = arrindex; + byte[] arrayOfByte1 = arrayOfByte; + + arrayOfByte1[n] = (byte) (arrayOfByte1[n] & (128 >> w % 8 ^ 0xFFFFFFFF)); + } + } + ++h; + //if ((++h - b1) * col >= 1024 || h == height) { + // str = bbbb(aaaaaa(arrayOfByte, m, arrindex - m + 1)); + // m = arrindex + 1; + // String str1 = "EG " + col + " " + (h - b1) + " " + start_x + " " + (start_y + b1) + " " + str + "\r\n"; + // + // System.out.println(str1); + // //b(str1); + // b1 = h; + // k++; + //} + } + + str = toHexString(copy(arrayOfByte, 0, arrindex + 1)); + System.out.println(str); + return str; + } + static String toHexString(byte[] paramArrayOfbyte) { + String str = ""; + for (int i = 0; i < paramArrayOfbyte.length; i++) { + String hex = Integer.toHexString(paramArrayOfbyte[i] & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + str = str + hex; + } + return str; + } + + private static byte[] copy(byte[] paramArrayOfbyte, int start, int length) { + byte[] arrayOfByte = new byte[length]; + for (int i = 0; i < length; i++) { + arrayOfByte[i] = paramArrayOfbyte[start + i]; + } + return arrayOfByte; + } } diff --git a/hiver-core/src/main/java/cc/hiver/core/vo/WechatVo.java b/hiver-core/src/main/java/cc/hiver/core/vo/WechatVo.java new file mode 100644 index 00000000..bb15a0dd --- /dev/null +++ b/hiver-core/src/main/java/cc/hiver/core/vo/WechatVo.java @@ -0,0 +1,28 @@ +package cc.hiver.core.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +@Data +@Accessors(chain = true) +public class WechatVo { + + @ApiModelProperty(value = "jsCode") + private String jsCode; + + @ApiModelProperty(value = "grantType") + private String grantType = "authorization_code"; + + @ApiModelProperty(value = "customId") + private String customId; + + @ApiModelProperty(value = "wechatName") + private String wechatName; + + @ApiModelProperty(value = "userType") + private String userType; + + @ApiModelProperty(value = "userId") + private String userId; +} diff --git a/hiver-modules/hiver-base/pom.xml b/hiver-modules/hiver-base/pom.xml index b2ebf1cf..e53e2d71 100644 --- a/hiver-modules/hiver-base/pom.xml +++ b/hiver-modules/hiver-base/pom.xml @@ -16,6 +16,18 @@ 1.0-SNAPSHOT compile + + + org.apache.httpcomponents + httpclient + 4.5.13 + + + + com.github.binarywang + weixin-java-mp + 4.6.0 + hiver-base diff --git a/hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/UserController.java b/hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/UserController.java index 22dc6119..8d9a3216 100644 --- a/hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/UserController.java +++ b/hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/UserController.java @@ -1,9 +1,12 @@ package cc.hiver.base.controller.manage; import cc.hiver.base.async.AddMessage; +import cc.hiver.core.common.annotation.SystemLog; import cc.hiver.core.common.constant.CommonConstant; +import cc.hiver.core.common.constant.MemberConstant; import cc.hiver.core.common.constant.SecurityConstant; import cc.hiver.core.common.constant.UserConstant; +import cc.hiver.core.common.enums.LogType; import cc.hiver.core.common.redis.RedisTemplateHelper; import cc.hiver.core.common.utils.*; import cc.hiver.core.common.vo.PageVo; @@ -17,13 +20,22 @@ import cc.hiver.core.entity.UserRole; import cc.hiver.core.service.*; import cc.hiver.core.service.mybatis.IUserRoleService; import cc.hiver.core.vo.RoleDTO; +import cc.hiver.core.vo.WechatVo; +import cc.hiver.mall.entity.Shop; +import cc.hiver.mall.entity.ShopUser; +import cc.hiver.mall.service.ShopService; +import cc.hiver.mall.service.ShopUserService; import cc.hiver.mall.service.mybatis.CustomerService; import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.http.HttpUtil; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.data.domain.Page; @@ -36,9 +48,7 @@ import javax.persistence.PersistenceContext; import javax.validation.Valid; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; /** @@ -91,6 +101,30 @@ public class UserController { @Autowired private CustomerService customerService; + @Value("${app.social.wxMini.appId}") + private String appId; + + @Value("${app.social.wxMini.appSecret}") + private String appSecret; + + private static final Integer TYPE = MemberConstant.MEMBER_PLATFORM_WECHAT; + + @Autowired + private ShopUserService shopUserService; + + @Autowired + private ShopService shopService; + + + @Autowired + private MemberSocialService memberSocialService; + + + /** + * 微信小程序登录凭证校验 + */ + private static final String JSCODETOSESSION_URL = "https://api.weixin.qq.com/sns/jscode2session"; + @RequestMapping(value = "/info", method = RequestMethod.GET) @ApiOperation("获取当前登录用户接口") public Result getUserInfo() { @@ -141,7 +175,7 @@ public class UserController { @ApiParam("手机号") @RequestParam String mobile, @ApiParam("旧密码") @RequestParam String password, @ApiParam("新密码") @RequestParam String newPass) { - if(StringUtils.isEmpty(mobile) && StringUtils.isEmpty(newPass)){ + if (StringUtils.isEmpty(mobile) && StringUtils.isEmpty(newPass)) { return ResultUtil.error("未修改任何信息!"); } final User user = userService.findById(userId); @@ -511,4 +545,191 @@ public class UserController { } return ResultUtil.success(message); } + + /** + * 根据userId更新user表mini_program_openid和unionid + * + * @param user + * @return Result + * @author 王富康 + * @date 2024/11/30 + */ + @RequestMapping(value = "/updateMiniProgramAndUnionid", method = RequestMethod.POST) + @ApiOperation("根据userId更新user表mini_program_openid和unionid") + public Result updateMiniProgramAndUnionid(@RequestBody User user) { + final User oldUser = userService.findById(user.getId()); + oldUser.setMiniProgramOpenid(user.getMiniProgramOpenid()); + oldUser.setUnionid(user.getUnionid()); + userService.update(oldUser); + return ResultUtil.success("更新成功"); + } + + + /** + * 获取微信小程序认证链接 + * + * @param wechatVo + * @return Result + * @author 王富康 + * @date 2024/12/3 + */ + @RequestMapping(value = "/login", method = RequestMethod.POST) + @ApiOperation("获取微信小程序认证链接") + @ResponseBody + @SystemLog(description = "微信小程序登录", type = LogType.MEMBER_LOGIN) + public Result login(@RequestBody WechatVo wechatVo) { + if (StringUtils.isEmpty(wechatVo.getJsCode())) { + return ResultUtil.error("您未同意授权"); + } + + final String jscode2sessionUrl = JSCODETOSESSION_URL + "?appid=" + appId + "&secret=" + appSecret + "&js_code=" + wechatVo.getJsCode() + + "&grant_type=" + wechatVo.getGrantType(); + // 申请openid + final String result = HttpUtil.get(jscode2sessionUrl); + if (!result.contains("session_key")) { + return ResultUtil.error("获取session_key失败"); + } + final JsonObject jsonObject = JsonParser.parseString(result).getAsJsonObject(); + final String sessionKey = jsonObject.get("session_key").getAsString(); + final String openId = jsonObject.get("openid").getAsString(); + final String unionid = jsonObject.get("unionid").getAsString(); + // 判断是否绑定用户 + User wechatUser = null; + final Map resultMap = new HashMap<>(); + if(StringUtils.isEmpty(wechatVo.getUserId())){ + wechatUser = userService.findByUnionid(unionid); + }else{ + wechatUser = userService.findById(wechatVo.getUserId()); + } + if (wechatUser == null) { + try { + // 新增用户信息 + wechatUser = new User(); + wechatUser.setStatus(UserConstant.USER_STATUS_NORMAL); + wechatUser = userService.save(wechatUser); + // 设置用户角色 + final UserRole userRole = new UserRole(); + final PageVo pageVo = new PageVo(); + pageVo.setPageNumber(1); + pageVo.setPageSize(1); + final Page roleCustomer = roleService.findByCondition("ROLE_CUSTOMER", PageUtil.initPage(pageVo)); + final Role role = roleCustomer.getContent().get(0); + //客户角色 + userRole.setRoleId(role.getId()); + userRole.setRoleName("客户"); + userRole.setUserId(wechatUser.getId()); + userRoleService.save(userRole); + // 更新客户信息,绑定登录用户 + customerService.updateUserId(wechatVo.getCustomId(), wechatUser.getId()); + // 返回当前登录人的信息 + resultMap.put("msg", "新增用户信息,并绑定成功!"); + resultMap.put("customId", wechatVo.getCustomId()); + } catch (Exception e) { + return ResultUtil.error(e.getMessage()); + } + } else { + // 更新客户信息,绑定登录用户 + customerService.updateUserId(wechatVo.getCustomId(), wechatUser.getId()); + } + wechatUser.setUnionid(unionid); + wechatUser.setWechatName(wechatVo.getWechatName()); + wechatUser.setMiniProgramOpenid(openId); + // 统一更新小程序的一些信息 + userService.save(wechatUser); + // 锁定当前登录用户的类型 + wechatUser.setType(wechatVo.getUserType()); + final String accessToken = securityUtil.getToken(userService.userToDTO(wechatUser), true); + resultMap.put("accessToken", accessToken); + // 返回当前登录人的信息 + resultMap.put("user", wechatUser); + + // 店铺登录的话,根据登录人查询所有关联的店铺(店铺启用,并且在有效期内) + if (UserConstant.USER_TYPE_NORMAL.equals(wechatUser.getType())) { + // 获取 + final List shopUsers = shopUserService.selectByUserId(wechatUser.getId()); + if (shopUsers != null && !shopUsers.isEmpty()) { + // 获取店主手机号 + for (ShopUser shopUser : shopUsers) { + final Shop shop = shopService.findById(shopUser.getShopId()); + if (shop != null && shop.getShopOwnerId() != null && StringUtils.isNotEmpty(shop.getShopOwnerId())) { + final User shopOwner = userService.findById(shop.getShopOwnerId()); + if (shopOwner != null) { + shopUser.setShopOwnerName(shopOwner.getNickname()); + shopUser.setShopOwnerPhone(shopOwner.getMobile()); + } + + } + } + resultMap.put("shopList", shopUsers); + } else { + return ResultUtil.error("店铺未开通!"); + } + } + return ResultUtil.data(resultMap); + } + + // 关注公众号-回调 + // 根据unionid查user表有没有数据,没有就新增一条user数据,同时绑定official_account_openid(公众号id)、unionid,有就更新一下official_account_openid + @RequestMapping(value = "/officialAccount", method = RequestMethod.GET) + @ApiOperation("关注公众号-回调") + public Result officialAccount(String openid, String unionid) { + if (StringUtils.isEmpty(unionid)) { + return ResultUtil.error("unionid不能为空!"); + } + // 判断是否绑定用户 + User wechatUser = userService.findByUnionid(unionid); + final Map resultMap = new HashMap<>(); + if (wechatUser != null) { + wechatUser.setOfficialAccountOpenid(openid); + } else { + try { + // 新增用户信息 + wechatUser = new User(); + wechatUser.setUnionid(unionid); + wechatUser.setOfficialAccountOpenid(openid); + wechatUser.setStatus(UserConstant.USER_STATUS_NORMAL); + wechatUser = userService.save(wechatUser); + // 设置用户角色 + final UserRole userRole = new UserRole(); + final PageVo pageVo = new PageVo(); + pageVo.setPageNumber(1); + pageVo.setPageSize(1); + final Page roleCustomer = roleService.findByCondition("ROLE_CUSTOMER", PageUtil.initPage(pageVo)); + final Role role = roleCustomer.getContent().get(0); + //客户角色 + userRole.setRoleId(role.getId()); + userRole.setRoleName("客户"); + userRole.setUserId(wechatUser.getId()); + userRoleService.save(userRole); + // 更新客户信息,绑定登录用户 + // customerService.updateUserId(wechatVo.getCustomId(),wechatUser.getId()); + // 返回当前登录人的信息 + resultMap.put("msg", "新增用户信息,并绑定成功!"); + // resultMap.put("customId", wechatVo.getCustomId()); + } catch (Exception e) { + return ResultUtil.error(e.getMessage()); + } + } + userService.save(wechatUser); + return ResultUtil.data(resultMap); + } + + /** + * mini_program_openid查询user表的所有信息 + * + * @param miniProgramOpenid + * @return Result + * @author 王富康 + * @date 2024/12/18 + */ + @RequestMapping(value = "/getUserInfo", method = RequestMethod.POST) + @ApiOperation("mini_program_openid查询user表的所有信息") + public Result getUserInfo(String miniProgramOpenid) { + if (StringUtils.isEmpty(miniProgramOpenid)) { + return ResultUtil.error("miniProgramOpenid!"); + } + return ResultUtil.data(userService.findByMiniProgramOpenid(miniProgramOpenid)); + } + + } diff --git a/hiver-modules/hiver-base/src/main/java/cc/hiver/base/utils/WeChatUtil.java b/hiver-modules/hiver-base/src/main/java/cc/hiver/base/utils/WeChatUtil.java new file mode 100644 index 00000000..8e40c49f --- /dev/null +++ b/hiver-modules/hiver-base/src/main/java/cc/hiver/base/utils/WeChatUtil.java @@ -0,0 +1,40 @@ +package cc.hiver.base.utils; + +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.jetbrains.annotations.Nullable; + +public class WeChatUtil { + + + private static final String APP_ID = "wx6d7d4fb58d1502db"; + private static final String APP_SECRET = "3a2c8cd00926764bbd12fd7361e01f1d"; + private static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}"; + + /** + * 获取Access Token + * @author 王富康 + * @date 2024/12/19 + * @return String + */ + @Nullable + public static String getAccessToken() throws Exception { + final String url = TOKEN_URL.replace("{}", APP_ID).replace("{}", APP_SECRET); + final HttpGet request = new HttpGet(url); + final CloseableHttpClient httpClient = HttpClients.createDefault(); + final String result = httpClient.execute(request, httpResponse -> + EntityUtils.toString(httpResponse.getEntity())); + // 解析JSON获取access_token,这里假设已经通过某种方式(如Jackson, Gson)解析 + // 这里简单用String.split()模拟解析 + final String[] parts = result.split(","); + for (String part : parts) { + if (part.contains("access_token")) { + final String[] tokenParts = part.split(":"); + return tokenParts[1].trim().replace("\"", ""); + } + } + return null; + } +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/CustomerController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/CustomerController.java index a5c4b93f..b2c2f048 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/CustomerController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/CustomerController.java @@ -226,8 +226,8 @@ public class CustomerController { @ApiOperation("根据用户id查询客户列表") public Result findByUserId(String userId,String shopId) { // shopId从缓存中设置 - final List list = customerService.findByUserId(userId,shopId); - return new ResultUtil>().setData(list); + final List list = customerService.findByUserId(userId,shopId); + return new ResultUtil>().setData(list); } @RequestMapping(value = "/findByUserName", method = RequestMethod.POST) @@ -252,11 +252,8 @@ public class CustomerController { @RequestMapping(value = "/findByUserPhoneAndShopId", method = RequestMethod.POST) @ApiOperation("根据客户手机号及店铺id精准查询查询客户列表") public Result findByUserPhoneAndShopId(String userPhone, String shopId) { - if(StringUtils.isEmpty(userPhone)){ - return ResultUtil.error("用户手机号不能为空"); - } - if(StringUtils.isEmpty(userPhone)){ - return ResultUtil.error("店铺id不能为空"); + if(StringUtils.isEmpty(userPhone) && StringUtils.isEmpty(userPhone)){ + return ResultUtil.error("用户手机号和店铺id不能都为空!"); } // shopId从缓存中设置 final List list = customerService.findByUserPhoneAndShopId(userPhone, shopId); @@ -307,4 +304,36 @@ public class CustomerController { final CustomerDataVo customerData = customerService.getCustomerData(customerPageQuery); return new ResultUtil().setData(customerData); } + + /** + * 根据customer表id更新userId字段 + * @author 王富康 + * @date 2024/11/30 + * @param customerId + * @param userId + * @return Result + */ + @RequestMapping(value = "/updateUserId", method = RequestMethod.POST) + @ApiOperation("根据customer表id更新userId字段") + public Result updateUserId(String customerId, String userId) { + if(StringUtils.isEmpty(customerId)){ + return ResultUtil.error("客户id不能为空"); + } + customerService.updateUserId(customerId, userId); + return ResultUtil.success("更新成功!"); + } + + // 根据userPhone更新userid + @RequestMapping(value = "/updateUserIdByUserPhone", method = RequestMethod.POST) + @ApiOperation("根据userPhone更新userid") + public Result updateUserIdByUserPhone(String userPhone, String userId) { + if(StringUtils.isEmpty(userPhone)){ + return ResultUtil.error("手机号不能为空"); + } + if(StringUtils.isEmpty(userId)){ + return ResultUtil.error("用户id不能为空"); + } + customerService.updateUserIdByUserPhone(userPhone, userId); + return ResultUtil.success("更新成功!"); + } } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/SaleController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/SaleController.java index 3c0520c5..a43e59de 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/SaleController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/SaleController.java @@ -14,6 +14,7 @@ import cc.hiver.core.entity.LogiticsCompany; import cc.hiver.core.entity.User; import cc.hiver.core.entity.Worker; import cc.hiver.core.service.LogiticsCompanyService; +import cc.hiver.core.service.UserService; import cc.hiver.core.service.WorkerService; import cc.hiver.core.vo.WorkerQueryVO; import cc.hiver.mall.common.constant.OrderConstant; @@ -107,6 +108,9 @@ public class SaleController { @Autowired private DebtService debtService; + @Autowired + private UserService userService; + @RequestMapping(value = "/buy", method = RequestMethod.POST) @ApiOperation("下单操作") @@ -238,7 +242,7 @@ public class SaleController { sale.setCreateBy(currUser.getId()); sale.setCreateByName(currUser.getNickname()); sale.setCreateByPhone(currUser.getMobile()); - if(sale.getCreateTime() == null) { + if (sale.getCreateTime() == null) { sale.setCreateTime(new Date()); } sale.setDelFlag(CommonConstant.DEL_FLAG_FALSE); @@ -255,9 +259,9 @@ public class SaleController { // 回填销售单id saleReturnDTO.getReturnSale().setSaleId(sale.getId()); // 时间 - if(sale.getCreateTime() == null) { + if (sale.getCreateTime() == null) { saleReturnDTO.getReturnSale().setCreateTime(new Date()); - }else{ + } else { saleReturnDTO.getReturnSale().setCreateTime(sale.getCreateTime()); } // 申请退货 @@ -397,8 +401,12 @@ public class SaleController { final QueryWrapper queryWrapper = new QueryWrapper<>(); final User user = securityUtil.getCurrUser(); // 查询下游客户的id - final List customerIdList = customerService.findByUserId(user.getId(),""); - queryWrapper.in("user_id", customerIdList); + final List customerIdList = customerService.findByUserId(user.getId(), ""); + List customerId = new ArrayList<>(); + for (Customer customer : customerIdList) { + customerId.add(customer.getId()); + } + queryWrapper.in("user_id", customerId); if (!ObjectUtils.isEmpty(saleVO)) { if (!StringUtils.isEmpty(saleVO.getPayStatus())) { queryWrapper.eq("pay_status", saleVO.getPayStatus()); @@ -586,6 +594,16 @@ public class SaleController { //增加客户信息明细 final String addCustomerId = sale.getUserId(); final Customer customer = customerService.getById(addCustomerId); + + if (customer != null && StringUtils.isNotEmpty(customer.getUserId())) { + final User user = userService.get(customer.getUserId()); + if (user != null) { + customer.setMiniProgramOpenid(user.getMiniProgramOpenid()); + customer.setUnionid(user.getUnionid()); + customer.setOfficialAccountOpenid(user.getOfficialAccountOpenid()); + customer.setWechatName(user.getWechatName()); + } + } saleNewVO.setCustomer(customer); // 增加物流公司信息 final String transCompanyId = sale.getTransCompany(); @@ -688,10 +706,10 @@ public class SaleController { startTime = saleVO.getStartTime() == null ? dateText : saleVO.getStartTime(); if (StringUtils.isEmpty(saleVO.getEndTime())) { // 为空,使用当前日期+1 - endTime = DateUtil.getAfterDayTime(dateText, 1); + endTime = DateUtil.addDay(dateText,1); } else { // 不为空,使用传参日期+1 - endTime = DateUtil.getAfterDayTime(saleVO.getEndTime(), 1); + endTime = DateUtil.addDay(saleVO.getEndTime(), 1); } saleAllVO = salesCalculateService.calculateService(startTime, endTime); // 获取本周营收统计 @@ -1179,11 +1197,11 @@ public class SaleController { @RequestMapping(value = "/buyAi", method = RequestMethod.POST) @ApiOperation("同步步Ai开单") - public Result buyAi(String aiMsg, String customerId,String productId) { + public Result buyAi(String aiMsg, String customerId, String productId) { if (StringUtils.isEmpty(aiMsg)) { ResultUtil.error("指令不能为空!"); } - JSONObject jsonObject = saleService.buyAi(aiMsg, customerId, productId); + final JSONObject jsonObject = saleService.buyAi(aiMsg, customerId, productId); return new ResultUtil().setData(jsonObject); } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/CustomerMapper.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/CustomerMapper.java index 85bb3941..538aaf2e 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/CustomerMapper.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/CustomerMapper.java @@ -39,15 +39,21 @@ public interface CustomerMapper extends BaseMapper { void delById(String id); - List findByUserId(@Param("userId") String userId,@Param("shopId") String shopId); + List findByUserId(@Param("userId") String userId, @Param("shopId") String shopId); - Page getCustomerList(Page page,@Param("queryParams") CustomerPageQuery customerPageQuery); + Page getCustomerList(Page page, @Param("queryParams") CustomerPageQuery customerPageQuery); - void updatePhone(@Param("newMobile")String newMobile,@Param("userId") String userId); + void updatePhone(@Param("newMobile") String newMobile, @Param("userId") String userId); boolean batchDeleteCustomer(@Param("idList") List idList); - List findByUserName(@Param("userName") String userName,@Param("shopId") String shopId); + List findByUserName(@Param("userName") String userName, @Param("shopId") String shopId); - List findByUserPhoneAndShopId(@Param("userPhone") String userPhone,@Param("shopId") String shopId); + List findByUserPhoneAndShopId(@Param("userPhone") String userPhone, @Param("shopId") String shopId); + + void updateUserId(@Param("customerId") String customerId, @Param("userId") String userId); + + List getOfficialAccountOpenids(@Param("shopId") String shopId, @Param("userId") String userId, @Param("categoryId") String categoryId, @Param("isAll") String isAll); + + void updateUserIdByUserPhone(@Param("userPhone")String userPhone,@Param("userId") String userId); } \ No newline at end of file diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Customer.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Customer.java index cc465666..17f116ed 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Customer.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Customer.java @@ -88,4 +88,20 @@ public class Customer implements Serializable { @ApiModelProperty(value = "排序字段") private String orderByField; + @TableField(exist = false) + @ApiModelProperty(value = "小程序id") + private String miniProgramOpenid; + + @TableField(exist = false) + @ApiModelProperty(value = "") + private String unionid; + + @TableField(exist = false) + @ApiModelProperty(value = "公众号id") + private String officialAccountOpenid; + + @TableField(exist = false) + @ApiModelProperty(value = "微信昵称") + private String wechatName; + } \ No newline at end of file diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/SaleQueryDTO.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/SaleQueryDTO.java index 110a744b..59b0a50b 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/SaleQueryDTO.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/SaleQueryDTO.java @@ -33,6 +33,9 @@ public class SaleQueryDTO implements Serializable { @ApiModelProperty(value = "客户id") private String userId; + @ApiModelProperty(value = "客户电话") + private String userPhone; + @ApiModelProperty(value = "客户名称") private String username; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/purchasereturn/service/impl/PurchaseReturnServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/purchasereturn/service/impl/PurchaseReturnServiceImpl.java index 0c7e050f..82fb31d5 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/purchasereturn/service/impl/PurchaseReturnServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/purchasereturn/service/impl/PurchaseReturnServiceImpl.java @@ -149,6 +149,7 @@ public class PurchaseReturnServiceImpl extends ServiceImpl { boolean deleteById(String id); - List findByUserId(String userId,String shopId); + List findByUserId(String userId, String shopId); Customer addCustomer(Customer customer); @@ -29,11 +29,12 @@ public interface CustomerService extends IService { /** * 根据客户手机号及店铺id精准查询查询客户列表 - * @author 王富康 - * @date 2024/9/6 + * * @param userPhone * @param shopId * @return List + * @author 王富康 + * @date 2024/9/6 */ List findByUserPhoneAndShopId(String userPhone, String shopId); @@ -41,10 +42,27 @@ public interface CustomerService extends IService { /** * 查询客户 拿货(总金额)商品总款数、总件数、退货(总金额)商品总款数、总件数 - * @author 王富康 - * @date 2024/10/24 + * * @param customerPageQuery * @return SupplierDataVo + * @author 王富康 + * @date 2024/10/24 */ CustomerDataVo getCustomerData(CustomerPageQuery customerPageQuery); + + /** + * 跟新客户登录用户id + * + * @param customerId + * @param userId + * @return Customer + * @author 王富康 + * @date 2024/11/30 + */ + void updateUserId(String customerId, String userId); + + // 获取符合条件的客户公众号id + List getOfficialAccountOpenids(String userId, String categoryId, String isAll); + + void updateUserIdByUserPhone(String userPhone, String userId); } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/SalesAndDetailsServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/SalesAndDetailsServiceImpl.java index bee4e812..a3a06df2 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/SalesAndDetailsServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/SalesAndDetailsServiceImpl.java @@ -455,8 +455,9 @@ public class SalesAndDetailsServiceImpl implements SalesAndDetailsService { String customerId = ""; if (StringUtils.isNotEmpty(saleQueryDTO.getMobile())) { // 20240906如果前台传了客户id了,不要新增客户了就 + byMobile = userService.findByMobile(saleQueryDTO.getMobile()); if(StringUtils.isEmpty(saleQueryDTO.getUserId())){ - byMobile = userService.findByMobile(saleQueryDTO.getMobile()); + // byMobile = userService.findByMobile(saleQueryDTO.getMobile()); if (byMobile == null) { //默认密码 final String encryptPass = new BCryptPasswordEncoder().encode("123456"); @@ -543,7 +544,14 @@ public class SalesAndDetailsServiceImpl implements SalesAndDetailsService { dealingsRecordService.save(dealingsRecord); }else{ // 客户id拿前台传的 - customerId = saleQueryDTO.getUserId(); + String byMobileMobile = byMobile.getMobile(); + if(byMobileMobile.equals(saleQueryDTO.getUserId())){ + customerId = saleQueryDTO.getUserId(); + }else{ + // 根据手机号查询的用户id和前台传的不一样,则根据 userPhone 查customer表(所有数据)更新 userid 为传过来的这个 + customerService.updateUserIdByUserPhone(saleQueryDTO.getMobile(),saleQueryDTO.getUserId()); + } + } } else { log.error("下游客户未填写手机号!"); diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/SalesCalculateServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/SalesCalculateServiceImpl.java index fb714302..0a13a764 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/SalesCalculateServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/SalesCalculateServiceImpl.java @@ -207,7 +207,7 @@ public class SalesCalculateServiceImpl implements SalesCalculateService { String searchDate; for (int i = -6; i < 1; i++) { // 查询的日期加一天 - searchDate = DateUtil.getAfterDayTime(todayDateStr, i); + searchDate = DateUtil.addDay(todayDateStr, i); // 店铺id从缓存中获取,并放到数据中去 final String shopId = securityUtil.getShopId(); // 查询日期范围内数据 diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/CustomerServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/CustomerServiceImpl.java index 4ca6b60c..5f938467 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/CustomerServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/CustomerServiceImpl.java @@ -84,7 +84,7 @@ public class CustomerServiceImpl extends ServiceImpl i } @Override - public List findByUserId(String userId,String shopId) { + public List findByUserId(String userId, String shopId) { return customerMapper.findByUserId(userId, shopId); } @@ -138,12 +138,12 @@ public class CustomerServiceImpl extends ServiceImpl i final String createBy; final String createByName; // shopId从缓存中设置 - if(StringUtils.isEmpty(customer.getShopId())){ + if (StringUtils.isEmpty(customer.getShopId())) { shopId = securityUtil.getShopId(); final User user = securityUtil.getCurrUser(); createBy = user.getId(); createByName = user.getNickname(); - }else{ + } else { shopId = customer.getShopId(); createBy = customer.getCreateBy(); createByName = customer.getCreateByName(); @@ -219,12 +219,12 @@ public class CustomerServiceImpl extends ServiceImpl i @Override public List findByUserName(String userName) { String shopId = securityUtil.getShopId(); - return customerMapper.findByUserName(userName,shopId); + return customerMapper.findByUserName(userName, shopId); } @Override public List findByUserPhoneAndShopId(String userPhone, String shopId) { - return customerMapper.findByUserPhoneAndShopId(userPhone,shopId); + return customerMapper.findByUserPhoneAndShopId(userPhone, shopId); } @Override @@ -232,19 +232,20 @@ public class CustomerServiceImpl extends ServiceImpl i Map result = new HashMap<>(); // 获取客户购买该商品规格的总件数 Integer buyCount = saleDetailService.getCustomerBuyHistory(productId, attributeList, customerId); - result.put("buyCount",buyCount); + result.put("buyCount", buyCount); // 获取客户购买该商品退货总件数 Integer returnCount = returnSaleService.getCustomerReturnHistory(productId, attributeList, customerId); - result.put("returnCount",returnCount); + result.put("returnCount", returnCount); return result; } /** * 查询客户 拿货(总金额)商品总款数、总件数、退货(总金额)商品总款数、总件数 - * @author 王富康 - * @date 2024/10/24 + * * @param customerPageQuery * @return SupplierDataVo + * @author 王富康 + * @date 2024/10/24 */ @Override public CustomerDataVo getCustomerData(CustomerPageQuery customerPageQuery) { @@ -261,4 +262,25 @@ public class CustomerServiceImpl extends ServiceImpl i customerDataVo.setReturnProductDataVos(returnSaleInfo.getReturnProductDataVos()); return customerDataVo; } + + @Override + public void updateUserId(String customerId, String userId) { + customerMapper.updateUserId(customerId, userId); + } + + @Override + public List getOfficialAccountOpenids(String userId, String categoryId, String isAll) { + + // shopId从缓存中设置 + final String shopId = securityUtil.getShopId(); + return customerMapper.getOfficialAccountOpenids(shopId, userId, categoryId, isAll); + } + + @Override + public void updateUserIdByUserPhone(String userPhone, String userId) { + customerMapper.updateUserIdByUserPhone(userPhone, userId); + // 根据userPhone获取用户信息 + userService.setUserPhoneToNull(userPhone); + userService.updateUserPhoneById(userPhone, userId); + } } diff --git a/hiver-modules/hiver-mall/src/main/resources/mapper/CustomerMapper.xml b/hiver-modules/hiver-mall/src/main/resources/mapper/CustomerMapper.xml index 37d65f49..b9e906cc 100644 --- a/hiver-modules/hiver-mall/src/main/resources/mapper/CustomerMapper.xml +++ b/hiver-modules/hiver-mall/src/main/resources/mapper/CustomerMapper.xml @@ -430,10 +430,11 @@ order by no_earn desc - select a.id, a.name, a.sex, a.phone, a.address, - a.province, a.city, a.area, a.shop_id, a.user_id, a.category_id, a.category_name,a.order_by_field,s.amount_owed as no_earn,t.not_buy_days + a.province, a.city, a.area, a.shop_id, a.user_id, a.category_id, a.category_name,a.order_by_field,s.amount_owed as no_earn,t.not_buy_days, + tu.mini_program_openid,tu.unionid,tu.official_account_openid,tu.wechat_name from t_customer a left join t_debt s on a.id = s.user_id @@ -442,6 +443,8 @@ where ts.shop_id = #{queryParams.shopId} group by ts.user_id) t on a.id = t.user_id + left join t_user tu + on a.user_id = tu.id where a.shop_id = #{queryParams.shopId} and a.del_flag = #{queryParams.delFlag} @@ -480,8 +483,9 @@ where id = #{id,jdbcType=VARCHAR} - + select + from t_customer a where a.user_id = #{userId,jdbcType=VARCHAR} @@ -518,7 +522,48 @@ from t_customer a where del_flag = '0' + and a.shop_id = #{shopId,jdbcType=VARCHAR} - and a.phone = #{userPhone,jdbcType=VARCHAR} + + + and a.user_id = #{userPhone,jdbcType=VARCHAR} + + + + + update t_customer + set user_id = #{userId,jdbcType=VARCHAR} + where id = #{customerId,jdbcType=VARCHAR} + + + + + + update t_customer + set user_id = #{userId,jdbcType=VARCHAR} + where phone = #{userPhone,jdbcType=VARCHAR} + \ No newline at end of file diff --git a/hiver-modules/hiver-social/pom.xml b/hiver-modules/hiver-social/pom.xml index 74984df2..c05eed74 100644 --- a/hiver-modules/hiver-social/pom.xml +++ b/hiver-modules/hiver-social/pom.xml @@ -7,6 +7,20 @@ cc.hiver 1.0-SNAPSHOT + + + com.github.binarywang + weixin-java-mp + 4.6.0 + compile + + + cc.hiver + hiver-mall + 1.0-SNAPSHOT + compile + + 4.0.0 Hiver社交模块 hiver-social diff --git a/hiver-modules/hiver-social/src/main/java/cc/hiver/social/config/MessageRouterConfig.java b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/config/MessageRouterConfig.java new file mode 100644 index 00000000..6f7e4650 --- /dev/null +++ b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/config/MessageRouterConfig.java @@ -0,0 +1,36 @@ +package cc.hiver.social.config; + +import cc.hiver.social.handler.WxServerMsgHandler; +import cc.hiver.social.interceptor.WxServerMsgInterceptor; +import me.chanjar.weixin.mp.api.WxMpMessageRouter; +import me.chanjar.weixin.mp.api.WxMpService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MessageRouterConfig { + + @Autowired + private WxMpService wxMpService; + + @Autowired + private WxServerMsgHandler wxServerMsgHandler; + + @Autowired + private WxServerMsgInterceptor wxServerMsgInterceptor; + + + @Bean + public WxMpMessageRouter messageRouter() { + // 创建消息路由 + final WxMpMessageRouter router = new WxMpMessageRouter(wxMpService); + // 添加一个同步处理文本消息的路由规则 同时添加interceptor、handler + router.rule() + .async(false) + .interceptor(wxServerMsgInterceptor) + .handler(wxServerMsgHandler) + .end(); + return router; + } +} diff --git a/hiver-modules/hiver-social/src/main/java/cc/hiver/social/config/WxMpConfiguration.java b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/config/WxMpConfiguration.java new file mode 100644 index 00000000..bd404847 --- /dev/null +++ b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/config/WxMpConfiguration.java @@ -0,0 +1,44 @@ +package cc.hiver.social.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.context.annotation.Configuration; + +@Configuration +public class WxMpConfiguration { + + @Autowired + private WxMpProperties wxMpProperties; + + + /** + * 微信客户端配置存储 + */ + @Bean + public WxMpConfigStorage wxMpConfigStorage() { + final WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl(); + // 设置微信公众号appId + configStorage.setAppId(wxMpProperties.getAppId()); + // 设置微信公众号appSecret + configStorage.setSecret(wxMpProperties.getSecret()); + // 设置微信公众号的token + configStorage.setToken(wxMpProperties.getToken()); + // 设置微信公众号的EncodingAESKey + configStorage.setAesKey(wxMpProperties.getAesKey()); + return configStorage; + } + + /** + * WxMpService多个实现类 声明一个实例 + */ + @Bean + public WxMpService wxMpService() { + final WxMpService wxMpService = new WxMpServiceImpl(); + wxMpService.setWxMpConfigStorage(wxMpConfigStorage()); + return wxMpService; + } +} diff --git a/hiver-modules/hiver-social/src/main/java/cc/hiver/social/config/WxMpProperties.java b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/config/WxMpProperties.java new file mode 100644 index 00000000..3ac4c489 --- /dev/null +++ b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/config/WxMpProperties.java @@ -0,0 +1,31 @@ +package cc.hiver.social.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@Data +@ConfigurationProperties(prefix = "wx.mp") +public class WxMpProperties { + + /** + * 设置微信公众号的appid + */ + private String appId; + + /** + * 设置微信公众号的app secret + */ + private String secret; + + /** + * 设置微信公众号的token + */ + private String token; + + /** + * 设置微信公众号的EncodingAESKey + */ + private String aesKey; +} diff --git a/hiver-modules/hiver-social/src/main/java/cc/hiver/social/controller/WechatController.java b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/controller/WechatController.java index 6ec82005..a1a9f9a2 100644 --- a/hiver-modules/hiver-social/src/main/java/cc/hiver/social/controller/WechatController.java +++ b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/controller/WechatController.java @@ -8,11 +8,13 @@ import cc.hiver.core.common.redis.RedisTemplateHelper; import cc.hiver.core.common.utils.ResultUtil; import cc.hiver.core.common.utils.SecurityUtil; import cc.hiver.core.common.vo.Result; +import cc.hiver.mall.service.mybatis.CustomerService; import cc.hiver.social.entity.Social; import cc.hiver.social.service.SocialService; +import cc.hiver.social.vo.WeChatServerMsgVo; import cc.hiver.social.vo.WechatUserInfo; +import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -20,16 +22,23 @@ import com.google.gson.JsonParser; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpMessageRouter; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; 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.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.*; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.TimeUnit; /** @@ -70,6 +79,15 @@ public class WechatController { @Autowired private RedisTemplateHelper redisTemplate; + @Autowired + private WxMpService wxMpService; + + @Autowired + private WxMpMessageRouter wxMpMessageRouter; + + @Autowired + private CustomerService customerService; + /** * 微信认证服务器地址 */ @@ -86,73 +104,175 @@ public class WechatController { private static final String GET_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo"; @RequestMapping(value = "/login", method = RequestMethod.GET) - @ApiOperation(value = "获取wechat认证链接") + @ApiOperation("获取wechat认证链接") @ResponseBody public Result login() throws UnsupportedEncodingException { // 生成并保存state 忽略该参数有可能导致CSRF攻击 - String state = String.valueOf(System.currentTimeMillis()); + final String state = String.valueOf(System.currentTimeMillis()); redisTemplate.set(STATE + state, "VALID", 3L, TimeUnit.MINUTES); // 传递参数response_type、client_id、state、redirect_uri - String url = AUTHORIZE_URL + "?appid=" + appId + "&redirect_uri=" + URLEncoder.encode(callbackUrl, "utf-8") + "&response_type=code" + + final String url = AUTHORIZE_URL + "?appid=" + appId + "&redirect_uri=" + URLEncoder.encode(callbackUrl, "utf-8") + "&response_type=code" + "&scope=snsapi_login&state=" + state; return ResultUtil.data(url); } @RequestMapping(value = "/callback", method = RequestMethod.GET) - @ApiOperation(value = "获取accessToken") + @ApiOperation("获取accessToken") @SystemLog(description = "微信关联登录", type = LogType.LOGIN) public String callback(@RequestParam(required = false) String code, @RequestParam(required = false) String state) throws UnsupportedEncodingException { - if (StrUtil.isBlank(code)) { + if (CharSequenceUtil.isBlank(code)) { return "redirect:" + callbackFeUrl + "?error=" + URLEncoder.encode("您未同意授权", "utf-8"); } // 验证state - String v = redisTemplate.get(STATE + state); + final String v = redisTemplate.get(STATE + state); redisTemplate.delete(STATE + state); - if (StrUtil.isBlank(v)) { + if (CharSequenceUtil.isBlank(v)) { return "redirect:" + callbackFeUrl + "?error=" + URLEncoder.encode("授权超时或state不正确", "utf-8"); } // 传递参数grant_type、code、redirect_uri、appid、appsecret - String accessTokenUrl = ACCESS_TOKEN_URL + "?appid=" + appId + "&secret=" + appSecret + "&code=" + code + + final String accessTokenUrl = ACCESS_TOKEN_URL + "?appid=" + appId + "&secret=" + appSecret + "&code=" + code + "&grant_type=authorization_code"; // 申请令牌 - String result = HttpUtil.get(accessTokenUrl); + final String result = HttpUtil.get(accessTokenUrl); if (!result.contains("access_token")) { return "redirect:" + callbackFeUrl + "?error=" + URLEncoder.encode("获取access_token失败", "utf-8"); } - JsonObject jsonObject = JsonParser.parseString(result).getAsJsonObject(); - String accessToken = jsonObject.get("access_token").getAsString(); - String openId = jsonObject.get("openid").getAsString(); + final JsonObject jsonObject = JsonParser.parseString(result).getAsJsonObject(); + final String accessToken = jsonObject.get("access_token").getAsString(); + final String openId = jsonObject.get("openid").getAsString(); // 获取用户信息 - String userInfo = HttpUtil.get(GET_USERINFO_URL + "?access_token=" + accessToken + "&openid=" + openId); - WechatUserInfo wu = new Gson().fromJson(userInfo, WechatUserInfo.class); + final String userInfo = HttpUtil.get(GET_USERINFO_URL + "?access_token=" + accessToken + "&openid=" + openId); + final WechatUserInfo wu = new Gson().fromJson(userInfo, WechatUserInfo.class); // 存入数据库 Social wechat = socialService.findByOpenIdAndPlatform(wu.getOpenid(), TYPE); if (wechat == null) { - Social w = new Social().setOpenId(wu.getOpenid()).setUsername(wu.getNickname()).setAvatar(wu.getHeadimgurl()).setPlatform(TYPE); + final Social w = new Social().setOpenId(wu.getOpenid()).setUsername(wu.getNickname()).setAvatar(wu.getHeadimgurl()).setPlatform(TYPE); wechat = socialService.save(w); } String url = ""; // 判断是否绑定账号 - if (StrUtil.isNotBlank(wechat.getRelateUsername())) { + if (CharSequenceUtil.isNotBlank(wechat.getRelateUsername())) { // 已绑定 直接登录 - String JWT = securityUtil.getToken(wechat.getRelateUsername(), true); + final String JWT = securityUtil.getToken(wechat.getRelateUsername(), true); // 存入redis - String JWTKey = IdUtil.simpleUUID(); + final String JWTKey = IdUtil.simpleUUID(); redisTemplate.set(JWTKey, JWT, 2L, TimeUnit.MINUTES); url = callbackFeUrl + "?related=1&JWTKey=" + JWTKey; } else { // 未绑定 Redis存入id - String idToken = IdUtil.simpleUUID(); + final String idToken = IdUtil.simpleUUID(); redisTemplate.set(idToken, wechat.getId(), 5L, TimeUnit.MINUTES); url = callbackFeRelateUrl + "?socialType=" + TYPE + "&id=" + idToken; } return "redirect:" + url; } + + @RequestMapping("echo") + @ResponseBody + public String configAccess(@RequestBody String requestBody, @RequestParam("signature") String signature, @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) { + // 校验签名 + if (!wxMpService.checkSignature(timestamp, nonce, signature)) { + log.error("签名校验 ===》 非法请求"); + // 消息签名不正确,说明不是公众平台发过来的消息 + return null; + } + log.error("签名校验 ===》 验证成功"); + + // 解析消息体,封装为对象 + final WxMpXmlMessage xmlMessage = WxMpXmlMessage.fromXml(requestBody); + WxMpXmlOutMessage outMessage = null; + try { + // 将消息路由给对应的处理器,获取响应 + outMessage = wxMpMessageRouter.route(xmlMessage); + } catch (Exception e) { + log.error("消息路由异常", e); + } + if (outMessage != null) { + log.info("到了返回了========" + outMessage.toXml()); + } else { + log.info("到了返回了========outMessage为空!"); + } + // 将响应消息转换为xml格式返回 + return outMessage == null ? null : outMessage.toXml(); + } + + /** + * 发送模版消息 + * + * @param weChatServerMsgVo 消息Vo + * @throws Exception + */ + @ResponseBody + @RequestMapping("sendWechatTempMessage") + public Result sendWechatTempMessage(@RequestBody WeChatServerMsgVo weChatServerMsgVo) throws Exception { + // 查询相关人员信息 + // 情况说明:1、upNewType,0零售价,1批发价,userId和categoryId为空,则按照零售价或者批发价推送给所有客户 + //1、如果传了userId,则只给这一个用户推送,这个客户有客户分类就是用客户分类价格,没有分类则使用批发价 + //2、如果传了categoryId,则只给该分类的客户推送 + //3、如果这三个参数都为空,则给全部客户推送,有客户分类按客户分类,没有按批发价推送 + // 获取店铺客户openId集合 + final List officialAccountOpenids = customerService.getOfficialAccountOpenids(weChatServerMsgVo.getUserId(), weChatServerMsgVo.getCategoryId(),weChatServerMsgVo.getIsAll()); + for (String openId : officialAccountOpenids) { + + final WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder() + // 要推送的用户openid + .toUser(openId) + // 消息详情跳转地址:https://blog.csdn.net/qq_34272760/article/details/120152903 + // 若需要跳转小程序,url则设置为:http://mp.weixin.qq.com,然后设置相关的MiniProgram参数【跳转的小程序必须是公众号关联的小程序!!!】 + .url("http://mp.weixin.qq.com") + // 微信模板ID + .templateId(weChatServerMsgVo.getTempId()) + .build(); + // data的字段及内容是自定义的,不必按我这儿的来,具体怎么和已有的系统消息结合,实现key和color可配置化需自行考虑 + final JsonObject jsonObject = JsonParser.parseString(weChatServerMsgVo.getContent()).getAsJsonObject(); + final List data = new ArrayList<>(); + for (String key : jsonObject.keySet()) { + final Object value = jsonObject.get(key); + String afterValue = String.valueOf(value).replace("\"", ""); + log.info("Key: " + key + ", Value: " + afterValue); + data.add(new WxMpTemplateData(key, afterValue)); + + } + templateMessage.setData(data); + + // 跳转小程序相关配置【跳转的小程序必须是公众号关联的小程序!!!】 + final WxMpTemplateMessage.MiniProgram miniProgram = new WxMpTemplateMessage.MiniProgram(); + log.info("appId============" + appId); + // 小程序的appId + miniProgram.setAppid(appId); + // 小程序的pagePath 注意,这里是支持传参的!!! + miniProgram.setPagePath(weChatServerMsgVo.getPagePath()); + // 需要跳转首页时,需要设置 usePath = true (默认是 false,只跳转非首页) + miniProgram.setUsePath(false); + templateMessage.setMiniProgram(miniProgram); + + try { + // 发送模板消息 + wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage); + } catch (Exception e) { + log.error("微信公众号模板消息推送失败,接收userId: " + openId, e); + return ResultUtil.error("发送失败" + e.getMessage()); + } + + } + return ResultUtil.success("发送成功!"); + } + + // 根据openid获取用户信息 + @ResponseBody + @RequestMapping("getUserInfo") + public Result getUserInfo(String openid) throws WxErrorException { + // 拼接请求地址 + String lang = "zh_CN"; //语言 + WxMpUser user = wxMpService.getUserService().userInfo(openid,lang); + return ResultUtil.data(user); + } + } diff --git a/hiver-modules/hiver-social/src/main/java/cc/hiver/social/handler/WxServerMsgHandler.java b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/handler/WxServerMsgHandler.java new file mode 100644 index 00000000..762b6f6c --- /dev/null +++ b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/handler/WxServerMsgHandler.java @@ -0,0 +1,67 @@ +package cc.hiver.social.handler; + +import cc.hiver.core.service.UserService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@Slf4j +public class WxServerMsgHandler implements WxMpMessageHandler { + + @Autowired + private UserService userService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService, WxSessionManager sessionManager) throws WxErrorException { + + log.info("接收到的消息MsgType:{};Event:{};OpenId:{};FromUser:{};",wxMessage.getMsgType(),wxMessage.getEvent(),wxMessage.getOpenId(),wxMessage.getFromUser()); + // 响应的消息内容 + String outContent = ""; + //判断是否是事件类型 + if(wxMessage.getMsgType().equals(WxConsts.XmlMsgType.EVENT)){ + //订阅 + if(wxMessage.getEvent().equals(WxConsts.EventType.SUBSCRIBE)){ + outContent = "【快衣店信息推送】欢迎您!致力于帮助服装店主们更好地进行商品管理和营销推广,我们会持续发布实用技巧、成功案例分析等内容。期待与您共同成长,共创辉煌业绩!"; + final String lang = "zh_CN"; //语言 + final WxMpUser user = wxMpService.getUserService().userInfo(wxMessage.getFromUser(),lang); + log.info("关注公众号的用户信息:user====:{}",user); + userService.subscribeWxServer(user); + } + //取消订阅 + if(wxMessage.getEvent().equals(WxConsts.EventType.UNSUBSCRIBE)){ + + } + } else if (wxMessage.getMsgType().equals(WxConsts.XmlMsgType.TEXT)){ + //判断为文本消息 + // 接收消息内容 + final String inContent = wxMessage.getContent(); + // 根据不同的关键字回复消息 + if (inContent.contains("hello")) { + outContent = "hello world"; + } else if (inContent.contains("java")) { + outContent = "hello java"; + } else if (inContent.contains("***")) { + outContent = "请文明用语"; + } else { + outContent = "服务繁忙,暂时不能回复"; + } + }else{ + outContent = "服务繁忙,暂时不能回复"; + } + log.info("outContent========"+outContent); + // 构造响应消息对象 + return WxMpXmlOutMessage.TEXT().content(outContent).fromUser(wxMessage.getToUser()) + .toUser(wxMessage.getFromUser()).build(); + } +} diff --git a/hiver-modules/hiver-social/src/main/java/cc/hiver/social/interceptor/WxServerMsgInterceptor.java b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/interceptor/WxServerMsgInterceptor.java new file mode 100644 index 00000000..bb3c56ac --- /dev/null +++ b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/interceptor/WxServerMsgInterceptor.java @@ -0,0 +1,29 @@ +package cc.hiver.social.interceptor; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageInterceptor; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 对微信公众号消息进行预处理、过滤等操作,根据具体业务需求决定是否允许继续执行后面的路由处理方法 + *

    + * 如果要中止消息的继续处理,即表示拦截了这个消息,需要返回 false。否则,在执行完当前拦截器操作后,允许消息的继续处理,返回 true + */ +@Component +public class WxServerMsgInterceptor implements WxMpMessageInterceptor { + + @Override + public boolean intercept(WxMpXmlMessage wxMpXmlMessage, Map map, WxMpService wxMpService, WxSessionManager wxSessionManager) { + final String msg = wxMpXmlMessage.getContent(); + final String msgType = wxMpXmlMessage.getMsgType(); + if ("text".equals(msgType) && msg.contains("混蛋")) { + wxMpXmlMessage.setContent("***"); + return true; + } + return true; + } +} \ No newline at end of file diff --git a/hiver-modules/hiver-social/src/main/java/cc/hiver/social/vo/WeChatServerMsgVo.java b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/vo/WeChatServerMsgVo.java new file mode 100644 index 00000000..a7a64cff --- /dev/null +++ b/hiver-modules/hiver-social/src/main/java/cc/hiver/social/vo/WeChatServerMsgVo.java @@ -0,0 +1,47 @@ +package cc.hiver.social.vo; + +import lombok.Data; + +@Data +public class WeChatServerMsgVo { + + /** + * 模版id + */ + private String tempId; + + /** + * 模版标头 + */ + private String title; + + /** + * 模版内容 + */ + private String content; + + /** + * 跳转小程序的页面 + */ + private String pagePath; + + /** + * 非必传 0零售价 1批发价 + */ + private String upNewType; + + /* + * 客户id + */ + private String userId; + + /** + * 客户分类id + */ + private String categoryId; + + /** + * isAIl=1的时候,则需要给该店铺所有没有绑定客户分类的客户推送消息 + */ + private String isAll; +}