微信小程序登录
This commit is contained in:
parent
91dab3510d
commit
2f68392778
@ -179,6 +179,12 @@
|
||||
<version>${wechatpay-apiv3.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- redis 缓存操作 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- httpclient 依赖-->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
package com.yf.exam.ability;
|
||||
|
||||
|
||||
/**
|
||||
* 通用常量
|
||||
* @author bool
|
||||
*/
|
||||
public class Constant {
|
||||
|
||||
|
||||
/**
|
||||
* 文件上传路径
|
||||
*/
|
||||
public static final String FILE_PREFIX = "/upload/file/";
|
||||
}
|
||||
@ -1,16 +1,14 @@
|
||||
package com.yf.exam.ability.shiro.aop;
|
||||
|
||||
|
||||
import com.yf.exam.ability.shiro.jwt.JwtToken;
|
||||
import com.yf.exam.aspect.utils.InjectUtils;
|
||||
import com.yf.exam.modules.Constant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
|
||||
|
||||
import com.yf.exam.constant.Constants;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
|
||||
|
||||
/**
|
||||
* 鉴权登录拦截器
|
||||
@ -42,7 +40,7 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
|
||||
@Override
|
||||
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||
String token = httpServletRequest.getHeader(Constant.TOKEN);
|
||||
String token = httpServletRequest.getHeader(Constants.TOKEN);
|
||||
|
||||
JwtToken jwtToken = new JwtToken(token);
|
||||
// 提交给realm进行登入,如果错误他会抛出异常并被捕获
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
package com.yf.exam.ability.upload.controller;
|
||||
|
||||
|
||||
import com.yf.exam.ability.Constant;
|
||||
import com.yf.exam.ability.upload.dto.UploadReqDTO;
|
||||
import com.yf.exam.ability.upload.dto.UploadRespDTO;
|
||||
import com.yf.exam.ability.upload.service.UploadService;
|
||||
import com.yf.exam.constant.Constants;
|
||||
import com.yf.exam.core.api.ApiRest;
|
||||
import com.yf.exam.core.api.controller.BaseController;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -16,9 +17,6 @@ import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 本地文件上传下载请求类
|
||||
* @author bool
|
||||
@ -49,7 +47,7 @@ public class UploadController extends BaseController {
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
@GetMapping(Constant.FILE_PREFIX+"**")
|
||||
@GetMapping(Constants.FILE_PREFIX+"**")
|
||||
@ApiOperation(value = "文件下载", notes = "文件下载")
|
||||
public void download(HttpServletRequest request, HttpServletResponse response) {
|
||||
uploadService.download(request, response);
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package com.yf.exam.ability.upload.service.impl;
|
||||
|
||||
import com.yf.exam.ability.Constant;
|
||||
import com.yf.exam.ability.upload.config.UploadConfig;
|
||||
import com.yf.exam.ability.upload.config.UploadPathConfig;
|
||||
import com.yf.exam.ability.upload.dto.UploadReqDTO;
|
||||
@ -155,7 +154,7 @@ public class UploadServiceImpl implements UploadService {
|
||||
*/
|
||||
public String getRealPath(String uri){
|
||||
|
||||
String regx = Constant.FILE_PREFIX+"(.*)";
|
||||
String regx = Constants.FILE_PREFIX+"(.*)";
|
||||
|
||||
// 查找全部变量
|
||||
Pattern pattern = Pattern.compile(regx);
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
package com.yf.exam.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @Description 微信小程序参数配置类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-09-02 10:52:38
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "applet-chat-config")
|
||||
public class AppletChatConfig {
|
||||
|
||||
/**
|
||||
* 小程序id
|
||||
*/
|
||||
private String appletId;
|
||||
|
||||
/**
|
||||
* 小程序secret
|
||||
*/
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* 返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语
|
||||
*/
|
||||
private String lang;
|
||||
|
||||
/**
|
||||
* 授权类型
|
||||
*/
|
||||
private String grantType;
|
||||
|
||||
/**
|
||||
* 微信小程序事件回调令牌
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 微信小程序事件回调消息加密密钥
|
||||
*/
|
||||
private String encodingAesKey;
|
||||
|
||||
}
|
||||
@ -50,6 +50,9 @@ public class ShiroConfig {
|
||||
map.put("/exam/api/sys/user/quick-reg", "anon");
|
||||
map.put("/exam/api/sys/user/info", "anon");
|
||||
|
||||
// 小程序接口
|
||||
map.put("/examApplet/**", "anon");
|
||||
|
||||
// 获取网站基本信息
|
||||
map.put("/exam/api/sys/config/detail", "anon");
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ package com.yf.exam.config;
|
||||
|
||||
import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import java.util.Collections;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -16,8 +17,6 @@ import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Swagger配置
|
||||
* @author bool
|
||||
@ -37,7 +36,8 @@ public class SwaggerConfig {
|
||||
.groupName("考试模块接口")
|
||||
.select()
|
||||
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
|
||||
.paths(PathSelectors.ant("/exam/api/**"))
|
||||
//.paths(PathSelectors.ant("/exam/api/**"))
|
||||
.paths(PathSelectors.any())
|
||||
.build()
|
||||
.securitySchemes(Collections.singletonList(securityScheme()));
|
||||
}
|
||||
|
||||
578
exam-admin/src/main/java/com/yf/exam/config/XinYiLuConfig.java
Normal file
578
exam-admin/src/main/java/com/yf/exam/config/XinYiLuConfig.java
Normal file
@ -0,0 +1,578 @@
|
||||
package com.yf.exam.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 读取项目相关配置
|
||||
*
|
||||
* @author xinyilu
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "xinyilu")
|
||||
public class XinYiLuConfig {
|
||||
/**
|
||||
* 项目名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 版权年份
|
||||
*/
|
||||
private String copyrightYear;
|
||||
|
||||
/**
|
||||
* 实例演示开关
|
||||
*/
|
||||
private boolean demoEnabled;
|
||||
|
||||
/**
|
||||
* 上传路径
|
||||
*/
|
||||
private static String profile;
|
||||
|
||||
/**
|
||||
* 获取地址开关
|
||||
*/
|
||||
private static boolean addressEnabled;
|
||||
|
||||
/**
|
||||
* 验证码类型
|
||||
*/
|
||||
private static String captchaType;
|
||||
|
||||
/**
|
||||
* 柏杏家医云小程序图片存放路径
|
||||
*/
|
||||
private String nurserAppletPicture;
|
||||
|
||||
/**
|
||||
* 护理站图片上传存放路径
|
||||
*/
|
||||
private String nurserStationPictureUrl;
|
||||
|
||||
/**
|
||||
* 护理站图片上传存放路径
|
||||
*/
|
||||
private String nurserStationIntroducePictureUrl;
|
||||
|
||||
/**
|
||||
* 护理站项目图片上传存放路径
|
||||
*/
|
||||
private String nurserStationItemPictureUrl;
|
||||
|
||||
/**
|
||||
* 商品图片路径上传存放路径
|
||||
*/
|
||||
private String goodsPictureUrl;
|
||||
|
||||
/**
|
||||
* 商品属性图片地址
|
||||
*/
|
||||
private String attributePitureUrl;
|
||||
|
||||
/**
|
||||
* 修改会员App用户头像上传
|
||||
*/
|
||||
private String headPictureUrl;
|
||||
|
||||
/**
|
||||
* 评价信息图片上传路径
|
||||
*/
|
||||
private String evaluatePictureUrl;
|
||||
|
||||
/**
|
||||
* 任务完成上传图片
|
||||
*/
|
||||
private String appointmentOrderDetailsUrl;
|
||||
|
||||
/**
|
||||
* 护理机构上传图片
|
||||
*/
|
||||
private String nurseStationClassifyUrl;
|
||||
|
||||
/**
|
||||
* 海报图片存放路径
|
||||
*/
|
||||
private String posterPictureUrl;
|
||||
|
||||
/**
|
||||
* 海报视频存放路径
|
||||
*/
|
||||
private String posterVideoUrl;
|
||||
|
||||
/**
|
||||
* 资讯主缩略图地址
|
||||
*/
|
||||
private String leadThumbnailUrl;
|
||||
|
||||
/**
|
||||
* 商品分类图片地址
|
||||
*/
|
||||
private String goodsCategoryPicture;
|
||||
|
||||
/**
|
||||
* 护理员App人员头像的上传路径图片上传路径
|
||||
*/
|
||||
private String nurseStationAppPersonUrl;
|
||||
|
||||
/**
|
||||
* 获取管理端富文本的上传路径
|
||||
*/
|
||||
private String richTextPictureUrl;
|
||||
|
||||
/**
|
||||
* 护理项目分类图标存放地址存放路径
|
||||
*/
|
||||
private String nurseItemClassifyUrl;
|
||||
|
||||
/**
|
||||
* 在线客服群二维码存放路径
|
||||
*/
|
||||
private String groupQrCodeUrl;
|
||||
|
||||
/**
|
||||
* 科室人员证书图片存放路径
|
||||
*/
|
||||
private String certificateUrl;
|
||||
|
||||
/**
|
||||
* 健康咨询 科室人员头像地址
|
||||
*/
|
||||
private String personPictureUrl;
|
||||
|
||||
/**
|
||||
* 护理人员证书地址
|
||||
*/
|
||||
private String personCertificateUrl;
|
||||
|
||||
/**
|
||||
* 审核护理人员证书地址
|
||||
*/
|
||||
private String personCertificateCheckUrl;
|
||||
|
||||
/**
|
||||
* 医路
|
||||
*/
|
||||
private String yiLuYouPinStoreName;
|
||||
|
||||
/**
|
||||
* 护理员App上传路径
|
||||
*/
|
||||
private String appFileName;
|
||||
|
||||
/**
|
||||
* 泉医到家App文件存放路径
|
||||
*/
|
||||
private String appFilePath;
|
||||
|
||||
/**
|
||||
* 培训分类图片路径
|
||||
*/
|
||||
private String trainingCategoryPictureUrl;
|
||||
|
||||
/**
|
||||
* 培训项目logo图片路径
|
||||
*/
|
||||
private String trainingItemCoverUrl;
|
||||
|
||||
/**
|
||||
* 培训项目海报图片路径
|
||||
*/
|
||||
private String trainingItemPosterUrl;
|
||||
|
||||
/**
|
||||
* 培训项目海报图片路径
|
||||
*/
|
||||
private String trainingItemContentUrl;
|
||||
|
||||
/**
|
||||
* 培训项目章节视频存放地址
|
||||
*/
|
||||
private String itemDirectoryUrl;
|
||||
|
||||
/**
|
||||
* 微信好有邀请二维码存放路径
|
||||
*/
|
||||
private String personalWeChatCodeUrl;
|
||||
|
||||
/**
|
||||
* 护理站二维码存放路径
|
||||
*/
|
||||
private String stationWechatCodeUrl;
|
||||
|
||||
/**
|
||||
* 实人认证身份证照片地址
|
||||
*/
|
||||
private String cardNoPicUrl;
|
||||
|
||||
/**
|
||||
* 预约订单护理项目告知书签字图片地址
|
||||
*/
|
||||
private String itemInformUrl;
|
||||
|
||||
public String getItemInformUrl() {
|
||||
return itemInformUrl;
|
||||
}
|
||||
|
||||
public void setItemInformUrl(String itemInformUrl) {
|
||||
this.itemInformUrl = itemInformUrl;
|
||||
}
|
||||
|
||||
public String getCardNoPicUrl() {
|
||||
return cardNoPicUrl;
|
||||
}
|
||||
|
||||
public void setCardNoPicUrl(String cardNoPicUrl) {
|
||||
this.cardNoPicUrl = cardNoPicUrl;
|
||||
}
|
||||
|
||||
public String getStationWechatCodeUrl() {
|
||||
return stationWechatCodeUrl;
|
||||
}
|
||||
|
||||
public void setStationWechatCodeUrl(String stationWechatCodeUrl) {
|
||||
this.stationWechatCodeUrl = stationWechatCodeUrl;
|
||||
}
|
||||
|
||||
public String getPersonalWeChatCodeUrl() {
|
||||
return personalWeChatCodeUrl;
|
||||
}
|
||||
|
||||
public void setPersonalWeChatCodeUrl(String personalWeChatCodeUrl) {
|
||||
this.personalWeChatCodeUrl = personalWeChatCodeUrl;
|
||||
}
|
||||
|
||||
public String getAppFilePath() {
|
||||
return appFilePath;
|
||||
}
|
||||
|
||||
public void setAppFilePath(String appFilePath) {
|
||||
this.appFilePath = appFilePath;
|
||||
}
|
||||
|
||||
public String getYiLuYouPinStoreName() {
|
||||
return yiLuYouPinStoreName;
|
||||
}
|
||||
|
||||
public void setYiLuYouPinStoreName(String yiLuYouPinStoreName) {
|
||||
this.yiLuYouPinStoreName = yiLuYouPinStoreName;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getCopyrightYear() {
|
||||
return copyrightYear;
|
||||
}
|
||||
|
||||
public void setCopyrightYear(String copyrightYear) {
|
||||
this.copyrightYear = copyrightYear;
|
||||
}
|
||||
|
||||
public boolean isDemoEnabled() {
|
||||
return demoEnabled;
|
||||
}
|
||||
|
||||
public void setDemoEnabled(boolean demoEnabled) {
|
||||
this.demoEnabled = demoEnabled;
|
||||
}
|
||||
|
||||
public static String getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public void setProfile(String profile) {
|
||||
XinYiLuConfig.profile = profile;
|
||||
}
|
||||
|
||||
public static boolean isAddressEnabled() {
|
||||
return addressEnabled;
|
||||
}
|
||||
|
||||
public void setAddressEnabled(boolean addressEnabled) {
|
||||
XinYiLuConfig.addressEnabled = addressEnabled;
|
||||
}
|
||||
|
||||
public static String getCaptchaType() {
|
||||
return captchaType;
|
||||
}
|
||||
|
||||
public void setCaptchaType(String captchaType) {
|
||||
XinYiLuConfig.captchaType = captchaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导入上传路径
|
||||
*/
|
||||
public static String getImportPath() {
|
||||
return getProfile() + "/import";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头像上传路径
|
||||
*/
|
||||
public static String getAvatarPath() {
|
||||
return getProfile() + "/avatar";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下载路径
|
||||
*/
|
||||
public static String getDownloadPath() {
|
||||
return getProfile() + "/download/";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传路径
|
||||
*/
|
||||
public static String getUploadPath() {
|
||||
return getProfile() + "/upload";
|
||||
}
|
||||
|
||||
public String getNurserAppletPicture() {
|
||||
return nurserAppletPicture;
|
||||
}
|
||||
|
||||
public void setNurserAppletPicture(String nurserAppletPicture) {
|
||||
this.nurserAppletPicture = nurserAppletPicture;
|
||||
}
|
||||
|
||||
public String getNurserStationPictureUrl() {
|
||||
return nurserStationPictureUrl;
|
||||
}
|
||||
|
||||
public void setNurserStationPictureUrl(String nurserStationPictureUrl) {
|
||||
this.nurserStationPictureUrl = nurserStationPictureUrl;
|
||||
}
|
||||
|
||||
public String getNurserStationIntroducePictureUrl() {
|
||||
return nurserStationIntroducePictureUrl;
|
||||
}
|
||||
|
||||
public void setNurserStationIntroducePictureUrl(String nurserStationIntroducePictureUrl) {
|
||||
this.nurserStationIntroducePictureUrl = nurserStationIntroducePictureUrl;
|
||||
}
|
||||
|
||||
public String getNurserStationItemPictureUrl() {
|
||||
return nurserStationItemPictureUrl;
|
||||
}
|
||||
|
||||
public void setNurserStationItemPictureUrl(String nurserStationItemPictureUrl) {
|
||||
this.nurserStationItemPictureUrl = nurserStationItemPictureUrl;
|
||||
}
|
||||
|
||||
public String getGoodsPictureUrl() {
|
||||
return goodsPictureUrl;
|
||||
}
|
||||
|
||||
public void setGoodsPictureUrl(String goodsPictureUrl) {
|
||||
this.goodsPictureUrl = goodsPictureUrl;
|
||||
}
|
||||
|
||||
public String getHeadPictureUrl() {
|
||||
return headPictureUrl;
|
||||
}
|
||||
|
||||
public void setHeadPictureUrl(String headPictureUrl) {
|
||||
this.headPictureUrl = headPictureUrl;
|
||||
}
|
||||
|
||||
public String getAppointmentOrderDetailsUrl() {
|
||||
return appointmentOrderDetailsUrl;
|
||||
}
|
||||
|
||||
public void setAppointmentOrderDetailsUrl(String appointmentOrderDetailsUrl) {
|
||||
this.appointmentOrderDetailsUrl = appointmentOrderDetailsUrl;
|
||||
}
|
||||
|
||||
public String getAttributePitureUrl() {
|
||||
return attributePitureUrl;
|
||||
}
|
||||
|
||||
public void setAttributePitureUrl(String attributePitureUrl) {
|
||||
this.attributePitureUrl = attributePitureUrl;
|
||||
}
|
||||
|
||||
|
||||
public String getAppFileName() {
|
||||
return appFileName;
|
||||
}
|
||||
|
||||
public void setAppFileName(String appFileName) {
|
||||
this.appFileName = appFileName;
|
||||
}
|
||||
|
||||
public String getNurseStationAppPersonUrl() {
|
||||
return nurseStationAppPersonUrl;
|
||||
}
|
||||
|
||||
public void setNurseStationAppPersonUrl(String nurseStationAppPersonUrl) {
|
||||
this.nurseStationAppPersonUrl = nurseStationAppPersonUrl;
|
||||
}
|
||||
|
||||
public String getEvaluatePictureUrl() {
|
||||
return evaluatePictureUrl;
|
||||
}
|
||||
|
||||
public void setEvaluatePictureUrl(String evaluatePictureUrl) {
|
||||
this.evaluatePictureUrl = evaluatePictureUrl;
|
||||
}
|
||||
|
||||
public String getRichTextPictureUrl() {
|
||||
return richTextPictureUrl;
|
||||
}
|
||||
|
||||
public void setRichTextPictureUrl(String richTextPictureUrl) {
|
||||
this.richTextPictureUrl = richTextPictureUrl;
|
||||
}
|
||||
|
||||
public String getGoodsCategoryPicture() {
|
||||
return goodsCategoryPicture;
|
||||
}
|
||||
|
||||
public void setGoodsCategoryPicture(String goodsCategoryPicture) {
|
||||
this.goodsCategoryPicture = goodsCategoryPicture;
|
||||
}
|
||||
|
||||
public String getNurseStationClassifyUrl() {
|
||||
return nurseStationClassifyUrl;
|
||||
}
|
||||
|
||||
public void setNurseStationClassifyUrl(String nurseStationClassifyUrl) {
|
||||
this.nurseStationClassifyUrl = nurseStationClassifyUrl;
|
||||
}
|
||||
|
||||
public String getNurseItemClassifyUrl() {
|
||||
return nurseItemClassifyUrl;
|
||||
}
|
||||
|
||||
public void setNurseItemClassifyUrl(String nurseItemClassifyUrl) {
|
||||
this.nurseItemClassifyUrl = nurseItemClassifyUrl;
|
||||
}
|
||||
|
||||
public String getPosterPictureUrl() {
|
||||
return posterPictureUrl;
|
||||
}
|
||||
|
||||
public void setPosterPictureUrl(String posterPictureUrl) {
|
||||
this.posterPictureUrl = posterPictureUrl;
|
||||
}
|
||||
|
||||
public String getLeadThumbnailUrl() {
|
||||
return leadThumbnailUrl;
|
||||
}
|
||||
|
||||
public void setLeadThumbnailUrl(String leadThumbnailUrl) {
|
||||
this.leadThumbnailUrl = leadThumbnailUrl;
|
||||
}
|
||||
|
||||
|
||||
public String getPosterVideoUrl() {
|
||||
return posterVideoUrl;
|
||||
}
|
||||
|
||||
public void setPosterVideoUrl(String posterVideoUrl) {
|
||||
this.posterVideoUrl = posterVideoUrl;
|
||||
}
|
||||
|
||||
|
||||
public String getGroupQrCodeUrl() {
|
||||
return groupQrCodeUrl;
|
||||
}
|
||||
|
||||
public void setGroupQrCodeUrl(String groupQrCodeUrl) {
|
||||
this.groupQrCodeUrl = groupQrCodeUrl;
|
||||
}
|
||||
|
||||
|
||||
public String getCertificateUrl() {
|
||||
return certificateUrl;
|
||||
}
|
||||
|
||||
public void setCertificateUrl(String certificateUrl) {
|
||||
this.certificateUrl = certificateUrl;
|
||||
}
|
||||
|
||||
public String getPersonPictureUrl() {
|
||||
return personPictureUrl;
|
||||
}
|
||||
|
||||
public void setPersonPictureUrl(String personPictureUrl) {
|
||||
this.personPictureUrl = personPictureUrl;
|
||||
}
|
||||
|
||||
public String getPersonCertificateUrl() {
|
||||
return personCertificateUrl;
|
||||
}
|
||||
|
||||
public void setPersonCertificateUrl(String personCertificateUrl) {
|
||||
this.personCertificateUrl = personCertificateUrl;
|
||||
}
|
||||
|
||||
public String getPersonCertificateCheckUrl() {
|
||||
return personCertificateCheckUrl;
|
||||
}
|
||||
|
||||
public void setPersonCertificateCheckUrl(String personCertificateCheckUrl) {
|
||||
this.personCertificateCheckUrl = personCertificateCheckUrl;
|
||||
}
|
||||
|
||||
public String getTrainingCategoryPictureUrl() {
|
||||
return trainingCategoryPictureUrl;
|
||||
}
|
||||
|
||||
public void setTrainingCategoryPictureUrl(String trainingCategoryPictureUrl) {
|
||||
this.trainingCategoryPictureUrl = trainingCategoryPictureUrl;
|
||||
}
|
||||
|
||||
public String getTrainingItemCoverUrl() {
|
||||
return trainingItemCoverUrl;
|
||||
}
|
||||
|
||||
public void setTrainingItemCoverUrl(String trainingItemCoverUrl) {
|
||||
this.trainingItemCoverUrl = trainingItemCoverUrl;
|
||||
}
|
||||
|
||||
public String getTrainingItemPosterUrl() {
|
||||
return trainingItemPosterUrl;
|
||||
}
|
||||
|
||||
public void setTrainingItemPosterUrl(String trainingItemPosterUrl) {
|
||||
this.trainingItemPosterUrl = trainingItemPosterUrl;
|
||||
}
|
||||
|
||||
public String getTrainingItemContentUrl() {
|
||||
return trainingItemContentUrl;
|
||||
}
|
||||
|
||||
public void setTrainingItemContentUrl(String trainingItemContentUrl) {
|
||||
this.trainingItemContentUrl = trainingItemContentUrl;
|
||||
}
|
||||
|
||||
public String getItemDirectoryUrl() {
|
||||
return itemDirectoryUrl;
|
||||
}
|
||||
|
||||
public void setItemDirectoryUrl(String itemDirectoryUrl) {
|
||||
this.itemDirectoryUrl = itemDirectoryUrl;
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @Description 新医路商户号微信支付参数配置类
|
||||
* @Description 山东省公共卫生学会商户号微信支付参数配置类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-17 16:55:04
|
||||
* @Version 1.0
|
||||
@ -16,27 +16,27 @@ import org.springframework.stereotype.Component;
|
||||
public class XylWeChatPaymentConfig {
|
||||
|
||||
/**
|
||||
* 新医路商户号
|
||||
* 山东省公共卫生学会商户号
|
||||
*/
|
||||
private String xylMchId;
|
||||
|
||||
/**
|
||||
* 新医路API证书序号getXylVerifier
|
||||
* 山东省公共卫生学会证书序号getXylVerifier
|
||||
*/
|
||||
private String xylMchSerialNo;
|
||||
|
||||
/**
|
||||
* 新医路私钥文件
|
||||
* 山东省公共卫生学会私钥文件
|
||||
*/
|
||||
private String xylPrivateKeyPath;
|
||||
|
||||
/**
|
||||
* 新医路API V3版本密钥
|
||||
* 山东省公共卫生学会API V3版本密钥
|
||||
*/
|
||||
private String xylPaymentKey;
|
||||
|
||||
/**
|
||||
* 新医路支付回调地址
|
||||
* 山东省公共卫生学会支付回调地址
|
||||
*/
|
||||
private String xylWeChatNotifyUrl;
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
/**
|
||||
* @Description 新医路商户号微信支付核心配置类
|
||||
* @Description 山东省公共卫生学会商户号微信支付核心配置类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-10-17 18:56:22
|
||||
* @Version 1.0
|
||||
@ -32,7 +32,7 @@ public class XylWeChatPaymentUtilConfig {
|
||||
private XylWeChatPaymentConfig xylWeChatPaymentConfig;
|
||||
|
||||
/**
|
||||
* 获取新医路签名信息
|
||||
* 获取山东省公共卫生学会签名信息
|
||||
*
|
||||
* @return 签名信息
|
||||
* @throws Exception 异常信息
|
||||
@ -54,36 +54,36 @@ public class XylWeChatPaymentUtilConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取新医路商户号带有签名的http请求对象
|
||||
* 获取山东省公共卫生学会商户号带有签名的http请求对象
|
||||
*
|
||||
* @return CloseableHttpClient对象
|
||||
*/
|
||||
@Bean(name = "xinYiLuWeChatPayClient")
|
||||
public CloseableHttpClient getXinYiLuWeChatPayClient(Verifier xylVerifier) {
|
||||
log.info("开始获取新医路商户带有签名信息的http请求对象........");
|
||||
log.info("开始获取山东省公共卫生学会商户带有签名信息的http请求对象........");
|
||||
//获取商户私钥
|
||||
PrivateKey privateKey = getPrivateKey(xylWeChatPaymentConfig.getXylPrivateKeyPath());
|
||||
CloseableHttpClient closeableHttpClient = null;
|
||||
try {
|
||||
log.info("新医路签名验证证书,xinYiLuCertificatesVerifier:{}", xylVerifier);
|
||||
log.info("山东省公共卫生学会签名验证证书,xinYiLuCertificatesVerifier:{}", xylVerifier);
|
||||
//通过WeChatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
|
||||
closeableHttpClient = WechatPayHttpClientBuilder.create()
|
||||
.withMerchant(xylWeChatPaymentConfig.getXylMchId(), xylWeChatPaymentConfig.getXylMchSerialNo(), privateKey)
|
||||
.withValidator(new WechatPay2Validator(xylVerifier)).build();
|
||||
} catch (Exception e) {
|
||||
log.error("新医路验证签名信息失败,失败信息:{}", e.getMessage());
|
||||
log.error("山东省公共卫生学会验证签名信息失败,失败信息:{}", e.getMessage());
|
||||
}
|
||||
return closeableHttpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取新医路商户号无签名的http请求对象
|
||||
* 获取山东省公共卫生学会商户号无签名的http请求对象
|
||||
*
|
||||
* @return CloseableHttpClient对象
|
||||
*/
|
||||
@Bean(name = "xinYiLuWeChatPayNoSignClient")
|
||||
public CloseableHttpClient getXinYiLuWeChatPayNoSignClient() {
|
||||
log.info("获取新医路商户的无签名信息的http请求对象.........");
|
||||
log.info("获取山东省公共卫生学会商户的无签名信息的http请求对象.........");
|
||||
//获取商户私钥
|
||||
PrivateKey privateKey = getPrivateKey(xylWeChatPaymentConfig.getXylPrivateKeyPath());
|
||||
//通过WeChatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
|
||||
@ -102,8 +102,8 @@ public class XylWeChatPaymentUtilConfig {
|
||||
try {
|
||||
return PemUtil.loadPrivateKey(new ClassPathResource(filename).getInputStream());
|
||||
} catch (Exception e) {
|
||||
log.error("新医路商户私钥文件不存在,错误原因:{}", e.getMessage());
|
||||
throw new ServiceException("新医路商户私钥文件不存在,请联系管理员!");
|
||||
log.error("山东省公共卫生学会商户私钥文件不存在,错误原因:{}", e.getMessage());
|
||||
throw new ServiceException("山东省公共卫生学会商户私钥文件不存在,请联系管理员!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,21 @@ package com.yf.exam.constant;
|
||||
*/
|
||||
public class Constants {
|
||||
|
||||
/**
|
||||
* UTF-8 字符集
|
||||
*/
|
||||
public static final String UTF8 = "UTF-8";
|
||||
|
||||
/**
|
||||
* 会话
|
||||
*/
|
||||
public static final String TOKEN = "token";
|
||||
|
||||
/**
|
||||
* 文件上传路径
|
||||
*/
|
||||
public static final String FILE_PREFIX = "/upload/file/";
|
||||
|
||||
/**
|
||||
* 身份证正面照片路径上传
|
||||
*/
|
||||
@ -42,6 +57,11 @@ public class Constants {
|
||||
*/
|
||||
public static final String sign_picture_type = "signPictureUrl";
|
||||
|
||||
/**
|
||||
* 微信小程序ACCESS_TOKEN前缀
|
||||
*/
|
||||
public static final String EXAM_APPLET_ACCESS_TOKEN = "EXAM_APPLET_ACCESS_TOKEN:";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
165
exam-admin/src/main/java/com/yf/exam/core/domain/AjaxResult.java
Normal file
165
exam-admin/src/main/java/com/yf/exam/core/domain/AjaxResult.java
Normal file
@ -0,0 +1,165 @@
|
||||
package com.yf.exam.core.domain;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* 操作消息提醒
|
||||
*
|
||||
* @author xinyilu
|
||||
*/
|
||||
public class AjaxResult extends HashMap<String, Object> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
public static final String CODE_TAG = "code";
|
||||
|
||||
/**
|
||||
* 返回内容
|
||||
*/
|
||||
public static final String MSG_TAG = "msg";
|
||||
|
||||
/**
|
||||
* 数据对象
|
||||
*/
|
||||
public static final String DATA_TAG = "data";
|
||||
|
||||
/**
|
||||
* 成功默认消息
|
||||
*/
|
||||
private static final Integer CODE_SUCCESS = 0;
|
||||
private static final String MSG_SUCCESS = "操作成功!";
|
||||
|
||||
/**
|
||||
* 失败默认消息
|
||||
*/
|
||||
private static final Integer CODE_FAILURE = 1;
|
||||
private static final String MSG_FAILURE = "请求失败!";
|
||||
|
||||
/**
|
||||
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
|
||||
*/
|
||||
public AjaxResult() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化一个新创建的 AjaxResult 对象
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param msg 返回内容
|
||||
*/
|
||||
public AjaxResult(int code, String msg) {
|
||||
super.put(CODE_TAG, code);
|
||||
super.put(MSG_TAG, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化一个新创建的 AjaxResult 对象
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param msg 返回内容
|
||||
* @param data 数据对象
|
||||
*/
|
||||
public AjaxResult(int code, String msg, Object data) {
|
||||
super.put(CODE_TAG, code);
|
||||
super.put(MSG_TAG, msg);
|
||||
if (!(data == null)) {
|
||||
super.put(DATA_TAG, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功消息
|
||||
*
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static AjaxResult success() {
|
||||
return AjaxResult.success("操作成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功数据
|
||||
*
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static AjaxResult success(Object data) {
|
||||
return AjaxResult.success("操作成功", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功消息
|
||||
*
|
||||
* @param msg 返回内容
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static AjaxResult success(String msg) {
|
||||
return AjaxResult.success(msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回成功消息
|
||||
*
|
||||
* @param msg 返回内容
|
||||
* @param data 数据对象
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static AjaxResult success(String msg, Object data) {
|
||||
return new AjaxResult(CODE_SUCCESS, msg, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误消息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static AjaxResult error() {
|
||||
return AjaxResult.error("操作失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误消息
|
||||
*
|
||||
* @param msg 返回内容
|
||||
* @return 警告消息
|
||||
*/
|
||||
public static AjaxResult error(String msg) {
|
||||
return AjaxResult.error(msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误消息
|
||||
*
|
||||
* @param msg 返回内容
|
||||
* @param data 数据对象
|
||||
* @return 警告消息
|
||||
*/
|
||||
public static AjaxResult error(String msg, Object data) {
|
||||
return new AjaxResult(CODE_FAILURE, msg, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误消息
|
||||
*
|
||||
* @param code 状态码
|
||||
* @param msg 返回内容
|
||||
* @return 警告消息
|
||||
*/
|
||||
public static AjaxResult error(int code, String msg) {
|
||||
return new AjaxResult(code, msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 方便链式调用
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return 数据对象
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult put(String key, Object value) {
|
||||
super.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
226
exam-admin/src/main/java/com/yf/exam/core/redis/RedisCache.java
Normal file
226
exam-admin/src/main/java/com/yf/exam/core/redis/RedisCache.java
Normal file
@ -0,0 +1,226 @@
|
||||
package com.yf.exam.core.redis;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.data.redis.core.BoundSetOperations;
|
||||
import org.springframework.data.redis.core.HashOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* spring redis 工具类
|
||||
*
|
||||
* @author xinyilu
|
||||
**/
|
||||
@SuppressWarnings(value = {"unchecked", "rawtypes"})
|
||||
@Component
|
||||
public class RedisCache {
|
||||
@Resource
|
||||
public RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
*/
|
||||
public <T> void setCacheObject(final String key, final T value) {
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
* @param timeout 时间
|
||||
* @param timeUnit 时间颗粒度
|
||||
*/
|
||||
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
|
||||
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param timeout 超时时间
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
public boolean expire(final String key, final long timeout) {
|
||||
return expire(key, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param timeout 超时时间
|
||||
* @param unit 时间单位
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
public boolean expire(final String key, final long timeout, final TimeUnit unit) {
|
||||
return redisTemplate.expire(key, timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象。
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
public <T> T getCacheObject(final String key) {
|
||||
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
||||
return operation.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单个对象
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public boolean deleteObject(final String key) {
|
||||
return redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除集合对象
|
||||
*
|
||||
* @param collection 多个对象
|
||||
* @return
|
||||
*/
|
||||
public long deleteObject(final Collection collection) {
|
||||
return redisTemplate.delete(collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存List数据
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param dataList 待缓存的List数据
|
||||
* @return 缓存的对象
|
||||
*/
|
||||
public <T> long setCacheList(final String key, final List<T> dataList) {
|
||||
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
|
||||
return count == null ? 0 : count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的list对象
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
public <T> List<T> getCacheList(final String key) {
|
||||
return redisTemplate.opsForList().range(key, 0, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存Set
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @param dataSet 缓存的数据
|
||||
* @return 缓存数据的对象
|
||||
*/
|
||||
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
|
||||
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
|
||||
Iterator<T> it = dataSet.iterator();
|
||||
while (it.hasNext()) {
|
||||
setOperation.add(it.next());
|
||||
}
|
||||
return setOperation;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的set
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public <T> Set<T> getCacheSet(final String key) {
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存Map
|
||||
*
|
||||
* @param key
|
||||
* @param dataMap
|
||||
*/
|
||||
public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
|
||||
if (dataMap != null) {
|
||||
redisTemplate.opsForHash().putAll(key, dataMap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的Map
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public <T> Map<String, T> getCacheMap(final String key) {
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 往Hash中存入数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @param value 值
|
||||
*/
|
||||
public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
|
||||
redisTemplate.opsForHash().put(key, hKey, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Hash中的数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @return Hash中的对象
|
||||
*/
|
||||
public <T> T getCacheMapValue(final String key, final String hKey) {
|
||||
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
|
||||
return opsForHash.get(key, hKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除Hash中的数据
|
||||
*
|
||||
* @param key
|
||||
* @param hKey
|
||||
*/
|
||||
public void delCacheMapValue(final String key, final String hKey) {
|
||||
HashOperations hashOperations = redisTemplate.opsForHash();
|
||||
hashOperations.delete(key, hKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多个Hash中的数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKeys Hash键集合
|
||||
* @return Hash对象集合
|
||||
*/
|
||||
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
|
||||
return redisTemplate.opsForHash().multiGet(key, hKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象列表
|
||||
*
|
||||
* @param pattern 字符串前缀
|
||||
* @return 对象列表
|
||||
*/
|
||||
public Collection<String> keys(final String pattern) {
|
||||
return redisTemplate.keys(pattern);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,277 @@
|
||||
package com.yf.exam.core.utils;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.yf.exam.config.AppletChatConfig;
|
||||
import com.yf.exam.config.XinYiLuConfig;
|
||||
import com.yf.exam.constant.Constants;
|
||||
import com.yf.exam.core.exception.ServiceException;
|
||||
import com.yf.exam.core.utils.http.HttpUtils;
|
||||
import com.yf.exam.modules.applet.entity.AppletAccessToken;
|
||||
import com.yf.exam.modules.applet.vo.AppletLoginVO;
|
||||
import com.yf.exam.modules.applet.vo.AppletPhoneVO;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @Description 微信小程序工具类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-08-17 16:11:10
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AppletChatUtil {
|
||||
|
||||
private static RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
private static AppletChatConfig appletChatConfig;
|
||||
|
||||
@Resource
|
||||
public void redisTemplate(RedisTemplate<String, Object> redisTemplate) {
|
||||
AppletChatUtil.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@Resource
|
||||
public void appletChatConfig(AppletChatConfig appletChatConfig) {
|
||||
AppletChatUtil.appletChatConfig = appletChatConfig;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 返回成功状态码
|
||||
*/
|
||||
private static final int SUCCESS_CODE = 0;
|
||||
|
||||
/**
|
||||
* 小程序登录url
|
||||
*/
|
||||
private static final String APPLET_LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session";
|
||||
|
||||
/**
|
||||
* 小程序accessToken的url
|
||||
*/
|
||||
private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
|
||||
|
||||
/**
|
||||
* 小程序获取用户手机号的url
|
||||
*/
|
||||
private static final String PHONE_NUMBER_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=";
|
||||
|
||||
/**
|
||||
* 获取小程序二维码接口地址
|
||||
*/
|
||||
private static final String GET_APPLET_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=";
|
||||
|
||||
/**
|
||||
* JSON数据格式标识
|
||||
*/
|
||||
private static final String JSON_DATA_FORMAT = "Content-Type: application/json; encoding=utf-8";
|
||||
|
||||
/**
|
||||
* 生成小程序二维码图片失败标识
|
||||
*/
|
||||
private static final String FAIL = "FAIL";
|
||||
|
||||
/**
|
||||
* 根据登录编码获取微信用户信息
|
||||
*
|
||||
* @param appletId 小程序id
|
||||
* @param secret 小程序秘钥
|
||||
* @param code 登录凭证码
|
||||
* @param grantType 授权类型
|
||||
* @return 登录信息
|
||||
*/
|
||||
public static AppletLoginVO getAppletLoginInfo(String appletId, String secret, String code, String grantType) {
|
||||
//请求地址
|
||||
String appletLoginUrl = APPLET_LOGIN_URL
|
||||
+ "?appid=" + appletId
|
||||
+ "&secret=" + secret
|
||||
+ "&js_code=" + code
|
||||
+ "&grant_type=" + grantType;
|
||||
//发送请求
|
||||
String result = HttpUtils.sendGet(appletLoginUrl);
|
||||
if (StringUtils.isBlank(result)) {
|
||||
throw new ServiceException("获取微信小程序用户信息失败");
|
||||
}
|
||||
return JSON.parseObject(result, AppletLoginVO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信小程序的accessToken
|
||||
*
|
||||
* @param appletId 小程序id
|
||||
* @param secret 小程序秘钥
|
||||
* @return accessToken信息
|
||||
*/
|
||||
public static AppletAccessToken getAppletAccessToken(String appletId, String secret) {
|
||||
//请求路径
|
||||
String accessTokenUrl = ACCESS_TOKEN_URL + "&appid=" + appletId + "&secret=" + secret;
|
||||
//发送请求
|
||||
String result = HttpUtils.sendGet(accessTokenUrl);
|
||||
if (StringUtils.isBlank(result)) {
|
||||
throw new ServiceException("获取微信小程序accessToken信息失败");
|
||||
}
|
||||
return JSON.parseObject(result, AppletAccessToken.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信小程序的手机号码
|
||||
*
|
||||
* @param code 登录凭证
|
||||
* @param accessToken 小程序accessToken
|
||||
* @return 手机信息
|
||||
*/
|
||||
public static AppletPhoneVO getAppletPhoneInfo(String code, String accessToken) {
|
||||
//请求地址
|
||||
String phoneUrl = PHONE_NUMBER_URL + accessToken;
|
||||
//请求参数
|
||||
Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("code", code);
|
||||
String param = JSON.toJSONString(paramMap);
|
||||
//发送POST请求
|
||||
String result = HttpUtils.sendPostJson(phoneUrl, param);
|
||||
if (StringUtils.isBlank(result)) {
|
||||
throw new ServiceException("获取微信小程序手机号失败");
|
||||
}
|
||||
return JSON.parseObject(result, AppletPhoneVO.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 递归获取小程序二维码信息
|
||||
*
|
||||
* @param weChatCodeId 输入id
|
||||
* @param failFlag 调用失败标识
|
||||
* @param fileName 文件名称
|
||||
* @param appletPageUrl 二维码跳转路径
|
||||
* @param filePathWeChatCodeUrl 文件保存路径
|
||||
* @return java.lang.String 二维码地址
|
||||
*/
|
||||
public static String createAppletCode(Long weChatCodeId, boolean failFlag, String fileName, String appletPageUrl, String filePathWeChatCodeUrl) {
|
||||
if (BooleanUtils.isTrue(failFlag)) {
|
||||
//删除原有Redis中的key值
|
||||
String accessTokenKey = Constants.EXAM_APPLET_ACCESS_TOKEN + "accessToken";
|
||||
Object object = redisTemplate.opsForValue().get(accessTokenKey);
|
||||
if (Objects.nonNull(object)) {
|
||||
redisTemplate.delete(accessTokenKey);
|
||||
}
|
||||
}
|
||||
//删除原有Redis中缓存的AccessToken
|
||||
String appletAccessToken = getAppletAccessToken();
|
||||
if (StringUtils.isBlank(appletAccessToken)) {
|
||||
throw new ServiceException("获取小程序凭证信息失败,请联系管理员!");
|
||||
}
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("scene", weChatCodeId);
|
||||
params.put("page", appletPageUrl);
|
||||
String body = JSON.toJSONString(params);
|
||||
String filePath = XinYiLuConfig.getProfile() + filePathWeChatCodeUrl + "/" + weChatCodeId;
|
||||
//调用微信接口获取小程序二维码并将其上传到服务器中
|
||||
return getAppletCodePicture(appletAccessToken, body, filePath, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据小程序AccessToken获取小程序的二维码图片
|
||||
*
|
||||
* @param accessToken 微信小程序的accessToken
|
||||
* @param body 接口传输参数
|
||||
* @param filePath 文件路径
|
||||
* @param fileName 文件名称
|
||||
* @return 小程序的二维码图片
|
||||
*/
|
||||
public static String getAppletCodePicture(String accessToken, String body, String filePath, String fileName) {
|
||||
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
||||
HttpPost httpPost = new HttpPost(GET_APPLET_CODE_URL + accessToken);
|
||||
try {
|
||||
StringEntity entity = new StringEntity(body, "UTF-8");
|
||||
entity.setContentType("image/png");
|
||||
httpPost.setEntity(entity);
|
||||
HttpResponse response = httpClient.execute(httpPost);
|
||||
String contentType = response.getEntity().getContentType().toString();
|
||||
if (StringUtils.equals(contentType, JSON_DATA_FORMAT)) {
|
||||
return FAIL;
|
||||
}
|
||||
String absolutePath = getAbsoluteFile(filePath, fileName).getAbsolutePath();
|
||||
try (InputStream inputStream = response.getEntity().getContent(); FileOutputStream out = new FileOutputStream(absolutePath)) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
out.flush();
|
||||
}
|
||||
return absolutePath;
|
||||
} catch (Exception e) {
|
||||
log.error("获取小程序二维码接口调用失败,失败原因为:{}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建文件路径
|
||||
*
|
||||
* @param uploadDir 路径名称
|
||||
* @param fileName 文件名称
|
||||
* @return File 文件目录
|
||||
*/
|
||||
public static File getAbsoluteFile(String uploadDir, String fileName) {
|
||||
File file = new File(uploadDir + File.separator + fileName);
|
||||
if (!file.exists()) {
|
||||
if (!file.getParentFile().exists()) {
|
||||
boolean mkdirs = file.getParentFile().mkdirs();
|
||||
if (BooleanUtils.isFalse(mkdirs)) {
|
||||
throw new ServiceException("文件路径创建失败,请联系管理员!");
|
||||
}
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取小程序AccessToken方法
|
||||
*
|
||||
* @return 小程序的AccessToken
|
||||
*/
|
||||
public static String getAppletAccessToken() {
|
||||
String accessToken;
|
||||
String accessTokenKey = Constants.EXAM_APPLET_ACCESS_TOKEN + "accessToken";
|
||||
//从Redis中取出accessToken
|
||||
Object object = redisTemplate.opsForValue().get(accessTokenKey);
|
||||
if (Objects.isNull(object)) {
|
||||
//没有,获取accessToken
|
||||
AppletAccessToken appletAccessToken = AppletChatUtil.getAppletAccessToken(appletChatConfig.getAppletId(), appletChatConfig.getSecret());
|
||||
if (Objects.isNull(appletAccessToken)) {
|
||||
throw new ServiceException("获取微信小程序accessToken信息失败");
|
||||
}
|
||||
if (Objects.nonNull(appletAccessToken.getErrcode()) && appletAccessToken.getErrcode() != SUCCESS_CODE) {
|
||||
throw new ServiceException("获取微信小程序accessToken信息失败,失败信息为:" + appletAccessToken.getErrmsg());
|
||||
}
|
||||
if (StringUtils.isBlank(appletAccessToken.getAccessToken())) {
|
||||
throw new ServiceException("accessToken信息为空");
|
||||
}
|
||||
//存入Redis中
|
||||
redisTemplate.opsForValue().set(accessTokenKey, appletAccessToken.getAccessToken(), 3600, TimeUnit.SECONDS);
|
||||
accessToken = appletAccessToken.getAccessToken();
|
||||
} else {
|
||||
accessToken = (String) object;
|
||||
}
|
||||
return accessToken;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.yf.exam.core.utils.http;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import javax.servlet.ServletRequest;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 通用http工具封装
|
||||
*
|
||||
* @author xinyilu
|
||||
*/
|
||||
public class HttpHelper {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(HttpHelper.class);
|
||||
|
||||
public static String getBodyString(ServletRequest request) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BufferedReader reader = null;
|
||||
try (InputStream inputStream = request.getInputStream()) {
|
||||
reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
||||
String line = "";
|
||||
while ((line = reader.readLine()) != null) {
|
||||
sb.append(line);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("getBodyString出现问题!");
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
LOGGER.error(ExceptionUtils.getMessage(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,297 @@
|
||||
package com.yf.exam.core.utils.http;
|
||||
|
||||
import com.yf.exam.constant.Constants;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.ConnectException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.Consts;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.utils.HttpClientUtils;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 通用http发送方法
|
||||
*
|
||||
* @author xinyilu
|
||||
*/
|
||||
public class HttpUtils {
|
||||
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
|
||||
|
||||
/**
|
||||
* 向指定 URL 发送GET方法的请求
|
||||
*
|
||||
* @param url 发送请求的 URL
|
||||
* @return 所代表远程资源的响应结果
|
||||
*/
|
||||
public static String sendGet(String url) {
|
||||
return sendGet(url, StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 向指定 URL 发送GET方法的请求
|
||||
*
|
||||
* @param url 发送请求的 URL
|
||||
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
||||
* @return 所代表远程资源的响应结果
|
||||
*/
|
||||
public static String sendGet(String url, String param) {
|
||||
return sendGet(url, param, Constants.UTF8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 向指定 URL 发送GET方法的请求
|
||||
*
|
||||
* @param url 发送请求的 URL
|
||||
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
||||
* @param contentType 编码类型
|
||||
* @return 所代表远程资源的响应结果
|
||||
*/
|
||||
public static String sendGet(String url, String param, String contentType) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
|
||||
log.info("sendGet - {}", urlNameString);
|
||||
URL realUrl = new URL(urlNameString);
|
||||
URLConnection connection = realUrl.openConnection();
|
||||
connection.setRequestProperty("accept", "*/*");
|
||||
connection.setRequestProperty("connection", "Keep-Alive");
|
||||
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
|
||||
connection.connect();
|
||||
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
result.append(line);
|
||||
}
|
||||
log.info("recv - {}", result);
|
||||
} catch (ConnectException e) {
|
||||
log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
|
||||
} catch (SocketTimeoutException e) {
|
||||
log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
|
||||
} catch (IOException e) {
|
||||
log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
|
||||
} catch (Exception e) {
|
||||
log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
|
||||
} finally {
|
||||
try {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 向指定 URL 发送POST方法的请求
|
||||
*
|
||||
* @param url 发送请求的 URL
|
||||
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
||||
* @return 所代表远程资源的响应结果
|
||||
*/
|
||||
public static String sendPost(String url, String param) {
|
||||
PrintWriter out = null;
|
||||
BufferedReader in = null;
|
||||
StringBuilder result = new StringBuilder();
|
||||
try {
|
||||
log.info("sendPost - {}", url);
|
||||
URL realUrl = new URL(url);
|
||||
URLConnection conn = realUrl.openConnection();
|
||||
conn.setRequestProperty("accept", "*/*");
|
||||
conn.setRequestProperty("connection", "Keep-Alive");
|
||||
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
|
||||
conn.setRequestProperty("Accept-Charset", "utf-8");
|
||||
conn.setRequestProperty("contentType", "utf-8");
|
||||
conn.setDoOutput(true);
|
||||
conn.setDoInput(true);
|
||||
out = new PrintWriter(conn.getOutputStream());
|
||||
out.print(param);
|
||||
out.flush();
|
||||
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
result.append(line);
|
||||
}
|
||||
log.info("recv - {}", result);
|
||||
} catch (ConnectException e) {
|
||||
log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
|
||||
} catch (SocketTimeoutException e) {
|
||||
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
|
||||
} catch (IOException e) {
|
||||
log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
|
||||
} catch (Exception e) {
|
||||
log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String sendSSLPost(String url, String param) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
String urlNameString = url + "?" + param;
|
||||
try {
|
||||
log.info("sendSSLPost - {}", urlNameString);
|
||||
SSLContext sc = SSLContext.getInstance("SSL");
|
||||
sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
|
||||
URL console = new URL(urlNameString);
|
||||
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
|
||||
conn.setRequestProperty("accept", "*/*");
|
||||
conn.setRequestProperty("connection", "Keep-Alive");
|
||||
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
|
||||
conn.setRequestProperty("Accept-Charset", "utf-8");
|
||||
conn.setRequestProperty("contentType", "utf-8");
|
||||
conn.setDoOutput(true);
|
||||
conn.setDoInput(true);
|
||||
|
||||
conn.setSSLSocketFactory(sc.getSocketFactory());
|
||||
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
|
||||
conn.connect();
|
||||
InputStream is = conn.getInputStream();
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
||||
String ret = "";
|
||||
while ((ret = br.readLine()) != null) {
|
||||
if (ret != null && !"".equals(ret.trim())) {
|
||||
result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
log.info("recv - {}", result);
|
||||
conn.disconnect();
|
||||
br.close();
|
||||
} catch (ConnectException e) {
|
||||
log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
|
||||
} catch (SocketTimeoutException e) {
|
||||
log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
|
||||
} catch (IOException e) {
|
||||
log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
|
||||
} catch (Exception e) {
|
||||
log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private static class TrustAnyTrustManager implements X509TrustManager {
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[]{};
|
||||
}
|
||||
}
|
||||
|
||||
private static class TrustAnyHostnameVerifier implements HostnameVerifier {
|
||||
@Override
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将通知参数转化为字符串
|
||||
*
|
||||
* @param request 请求信息
|
||||
* @return 请求参数信息
|
||||
*/
|
||||
public static String readRequestData(HttpServletRequest request) {
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
StringBuilder result = new StringBuilder();
|
||||
br = request.getReader();
|
||||
for (String line; (line = br.readLine()) != null; ) {
|
||||
if (result.length() > 0) {
|
||||
result.append("\n");
|
||||
}
|
||||
result.append(line);
|
||||
}
|
||||
return result.toString();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (br != null) {
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发送json格式的POST类型的http请求
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param param json格式的请求参数
|
||||
* @return String 返回值信息
|
||||
*/
|
||||
public static String sendPostJson(String url, String param) {
|
||||
String result = null;
|
||||
CloseableHttpClient httpClient = null;
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
httpClient = HttpClients.createDefault();
|
||||
// 字符串编码
|
||||
StringEntity entity = new StringEntity(param, Consts.UTF_8);
|
||||
// 设置content-type
|
||||
entity.setContentType("application/json");
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
httpPost.setConfig(RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000).build());
|
||||
// 防止被当成攻击添加的
|
||||
httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/54.0.2840.87 Safari/537.36");
|
||||
// 接收参数设置
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
httpPost.setEntity(entity);
|
||||
response = httpClient.execute(httpPost);
|
||||
HttpEntity httpEntity = response.getEntity();
|
||||
result = EntityUtils.toString(httpEntity);
|
||||
} catch (Exception e) {
|
||||
log.warn("post请求发送失败,请求路径:[{}],请求参数:[{}],异常信息:[{}]", url, param, e);
|
||||
} finally {
|
||||
HttpClientUtils.closeQuietly(response);
|
||||
HttpClientUtils.closeQuietly(httpClient);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.yf.exam.core.utils.regex;
|
||||
|
||||
import com.yf.exam.core.exception.ServiceException;
|
||||
import java.util.regex.Pattern;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @Description 正则表达式工具类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-08-24 13:58:48
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Component
|
||||
public class RegexUtil {
|
||||
|
||||
/**
|
||||
* 校验手机号码
|
||||
*
|
||||
* @param phone 手机号码
|
||||
* @return 校验结果
|
||||
*/
|
||||
public boolean regexPhone(String phone) {
|
||||
if (StringUtils.isBlank(phone)) {
|
||||
throw new ServiceException("手机号码不能为空!");
|
||||
}
|
||||
//校验手机号
|
||||
String regex = "^(((13[0-9]{1})|(14[0-9]{1})|(15[0-9]{1})|(16[2567]{1})|(17[0-9]{1})|(18[0-9]{1})|(19[0-9]{1}))+\\d{8})$";
|
||||
return Pattern.matches(regex, phone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验身份证号码
|
||||
*
|
||||
* @param cardNo 身份证号码
|
||||
* @return 校验结果
|
||||
*/
|
||||
public boolean regexCardNo(String cardNo) {
|
||||
if (StringUtils.isBlank(cardNo)) {
|
||||
throw new ServiceException("身份证号不能为空!");
|
||||
}
|
||||
//校验身份证号码
|
||||
String regex = "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|" +
|
||||
"(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)";
|
||||
return Pattern.matches(regex, cardNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验座机手机号码
|
||||
*
|
||||
* @param seatNumber 座机手机号码
|
||||
* @return 校验结果
|
||||
*/
|
||||
public boolean regexSeatNumber(String seatNumber) {
|
||||
if (StringUtils.isBlank(seatNumber)) {
|
||||
throw new ServiceException("手机号码不能为空!");
|
||||
}
|
||||
//校验座机手机号
|
||||
String regex = "^(([0-9]{4,13}))";
|
||||
return Pattern.matches(regex, seatNumber);
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
package com.yf.exam.modules;
|
||||
|
||||
|
||||
/**
|
||||
* 通用常量
|
||||
* @author bool
|
||||
*/
|
||||
public class Constant {
|
||||
|
||||
/**
|
||||
* 会话
|
||||
*/
|
||||
public static final String TOKEN = "token";
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
package com.yf.exam.modules.applet.controller;
|
||||
|
||||
import com.yf.exam.core.api.controller.BaseController;
|
||||
import com.yf.exam.core.domain.AjaxResult;
|
||||
import com.yf.exam.core.utils.regex.RegexUtil;
|
||||
import com.yf.exam.modules.applet.service.AppletLoginService;
|
||||
import com.yf.exam.modules.sys.user.dto.SysUserDTO;
|
||||
import com.yf.exam.modules.sys.user.service.SysUserService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @description: 微信小程序登录注册控制器
|
||||
* @author: haown
|
||||
* @create: 2025-08-11 16:05
|
||||
**/
|
||||
@Api(tags={"微信小程序"})
|
||||
@RestController
|
||||
@RequestMapping("/examApplet")
|
||||
public class AppletLoginController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private AppletLoginService appletLoginService;
|
||||
|
||||
@Resource
|
||||
private SysUserService sysUserService;
|
||||
@Resource
|
||||
private RegexUtil regexUtil;
|
||||
|
||||
/**
|
||||
* 注册用户信息
|
||||
*
|
||||
* @param reqDTO 输入参数
|
||||
* @return 结果
|
||||
*/
|
||||
@ApiOperation(value = "注册用户信息")
|
||||
@PostMapping("/register")
|
||||
public AjaxResult registerUserInfo(@RequestBody SysUserDTO reqDTO) {
|
||||
//校验手机号
|
||||
boolean regexPhone = regexUtil.regexPhone(StringUtils.isBlank(reqDTO.getPhone()) ? "" : reqDTO.getPhone());
|
||||
if (BooleanUtils.isFalse(regexPhone)) {
|
||||
return AjaxResult.error("您输入的手机号不正确,请重新输入!");
|
||||
}
|
||||
//校验身份证号
|
||||
boolean cardNo = regexUtil.regexCardNo(StringUtils.isBlank(reqDTO.getUserName()) ? "" : reqDTO.getUserName());
|
||||
if (BooleanUtils.isFalse(cardNo)) {
|
||||
return AjaxResult.error("您输入的身份证号不正确,请重新输入!");
|
||||
}
|
||||
return AjaxResult.success(sysUserService.reg(reqDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据登录凭证获取用户的登录信息
|
||||
*
|
||||
* @param loginCode 登录凭证
|
||||
* @return 微信用户登录信息
|
||||
*/
|
||||
@ApiOperation(value = "根据登录凭证获取用户的登录信息")
|
||||
@GetMapping("/appletLogin")
|
||||
public AjaxResult appletLogin(@RequestParam("loginCode") String loginCode) {
|
||||
if (StringUtils.isBlank(loginCode)) {
|
||||
return AjaxResult.error("登录凭证编码不能为空!");
|
||||
}
|
||||
//if (StringUtils.isBlank(phoneCode)) {
|
||||
// return AjaxResult.error("获取手机号凭证不存在");
|
||||
//}
|
||||
return appletLoginService.appletLogin(loginCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据openid判断当前用户信息是否存在,微信小程序登录页使用
|
||||
*
|
||||
* @param openId 微信用户的openid
|
||||
* @return 标识,LOGIN:已登录,NOT_LOGIN:未登录
|
||||
*/
|
||||
@GetMapping("/existUserInfo")
|
||||
public AjaxResult existUserInfo(String openId) {
|
||||
if (StringUtils.isBlank(openId)) {
|
||||
return AjaxResult.error("用户微信唯一标识不存在!");
|
||||
}
|
||||
return appletLoginService.existUserInfo(openId);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.yf.exam.modules.applet.entity;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description 微信小程序accessToken信息实体类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-08-17 17:05:10
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class AppletAccessToken implements Serializable {
|
||||
private static final long serialVersionUID = 7351002130502802480L;
|
||||
/**
|
||||
* accessToken值
|
||||
*/
|
||||
@JSONField(name = "access_token")
|
||||
private String accessToken;
|
||||
|
||||
/**
|
||||
* access_token有效时间,有效时间为7200秒
|
||||
*/
|
||||
@JSONField(name = "expires_in")
|
||||
private String expiresIn;
|
||||
|
||||
/**
|
||||
* 错误状态码
|
||||
* 40001:AppSecret 错误或者 AppSecret 不属于这个小程序,请开发者确认 AppSecret 的正确性
|
||||
* 40002:请确保 grant_type 字段值为 client_credential
|
||||
* 40013:不合法的 AppID,请开发者检查 AppID 的正确性,避免异常字符,注意大小写
|
||||
*/
|
||||
private Integer errcode;
|
||||
|
||||
/**
|
||||
* 错误状态值
|
||||
* 40001:AppSecret 错误或者 AppSecret 不属于这个小程序,请开发者确认 AppSecret 的正确性
|
||||
* 40002:请确保 grant_type 字段值为 client_credential
|
||||
* 40013:不合法的 AppID,请开发者检查 AppID 的正确性,避免异常字符,注意大小写
|
||||
*/
|
||||
private String errmsg;
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.yf.exam.modules.applet.service;
|
||||
|
||||
import com.yf.exam.core.domain.AjaxResult;
|
||||
|
||||
/**
|
||||
* @description: 微信小程序登录注册业务层
|
||||
* @author: haown
|
||||
* @create: 2025-08-11 16:05
|
||||
**/
|
||||
public interface AppletLoginService {
|
||||
|
||||
/**
|
||||
* 根据登录凭证获取用户的登录信息
|
||||
*
|
||||
* @param loginCode 登录凭证
|
||||
* @return 微信用户登录信息
|
||||
*/
|
||||
AjaxResult appletLogin(String loginCode);
|
||||
|
||||
/**
|
||||
* 根据openid判断当前用户信息是否存在,微信小程序登录页使用
|
||||
*
|
||||
* @param openId 微信用户的openid
|
||||
* @return 用户列表
|
||||
*/
|
||||
AjaxResult existUserInfo(String openId);
|
||||
}
|
||||
@ -0,0 +1,147 @@
|
||||
package com.yf.exam.modules.applet.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.yf.exam.config.AppletChatConfig;
|
||||
import com.yf.exam.constant.Constants;
|
||||
import com.yf.exam.core.domain.AjaxResult;
|
||||
import com.yf.exam.core.utils.AppletChatUtil;
|
||||
import com.yf.exam.modules.applet.service.AppletLoginService;
|
||||
import com.yf.exam.modules.applet.vo.AppletLoginVO;
|
||||
import com.yf.exam.modules.sys.user.entity.SysUser;
|
||||
import com.yf.exam.modules.sys.user.service.SysUserService;
|
||||
import com.yf.exam.modules.utils.AppletAccessTokenUtil;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @Description 微信小程序登录注册业务层实现类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-09-02 10:55:29
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class AppletLoginServiceImpl implements AppletLoginService {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
@Resource
|
||||
private AppletChatConfig appletChatConfig;
|
||||
@Resource
|
||||
private AppletAccessTokenUtil appletAccessTokenUtil;
|
||||
@Resource
|
||||
private SysUserService sysUserService;
|
||||
|
||||
/**
|
||||
* 返回成功状态码
|
||||
*/
|
||||
private static final int SUCCESS_CODE = 0;
|
||||
|
||||
/**
|
||||
* 返回成功状态码
|
||||
*/
|
||||
private static final String OK = "ok";
|
||||
|
||||
/**
|
||||
* 获取微信小程序access_token错误码
|
||||
*/
|
||||
private static final int ERROR_ACCESS_CODE = 40001;
|
||||
|
||||
|
||||
/**
|
||||
* 根据登录凭证获取用户的登录信息
|
||||
*
|
||||
* @param loginCode 登录凭证
|
||||
* @return 微信用户登录信息
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult appletLogin(String loginCode) {
|
||||
//根据code获取用户的微信unionId以及openId等信息
|
||||
AppletLoginVO appletLoginInfo = AppletChatUtil.getAppletLoginInfo(appletChatConfig.getAppletId(), appletChatConfig.getSecret(), loginCode, appletChatConfig.getGrantType());
|
||||
if (Objects.isNull(appletLoginInfo)) {
|
||||
return AjaxResult.error("获取微信小程序用户信息失败");
|
||||
}
|
||||
if (Objects.nonNull(appletLoginInfo.getErrcode()) && appletLoginInfo.getErrcode() != SUCCESS_CODE) {
|
||||
return AjaxResult.error("获取微信小程序用户信息失败,失败信息为:" + appletLoginInfo.getErrmsg());
|
||||
}
|
||||
//获取微信accessToken
|
||||
String accessToken;
|
||||
String accessTokenKey = Constants.EXAM_APPLET_ACCESS_TOKEN + "accessToken";
|
||||
//从Redis中取出accessToken
|
||||
Object object = redisTemplate.opsForValue().get(accessTokenKey);
|
||||
if (Objects.isNull(object)) {
|
||||
//没有,获取accessToken
|
||||
accessToken = appletAccessTokenUtil.getAppletAccessToken();
|
||||
} else {
|
||||
accessToken = (String) object;
|
||||
}
|
||||
//获取用户手机号
|
||||
|
||||
//AppletPhoneVO appletPhoneInfo = AppletChatUtil.getAppletPhoneInfo(phoneCode, accessToken);
|
||||
//if (Objects.isNull(appletPhoneInfo)) {
|
||||
// return AjaxResult.error("获取用户手机号失败");
|
||||
//}
|
||||
//if (Objects.nonNull(appletPhoneInfo.getErrcode()) && appletPhoneInfo.getErrcode() == ERROR_ACCESS_CODE) {
|
||||
// //当前Redis缓存中的access_token无效直接删除
|
||||
// if (Objects.nonNull(object)) {
|
||||
// redisTemplate.delete(accessTokenKey);
|
||||
// //删除之后重新获取获取accessToken
|
||||
// accessToken = appletAccessTokenUtil.getAppletAccessToken();
|
||||
// appletPhoneInfo = AppletChatUtil.getAppletPhoneInfo(phoneCode, accessToken);
|
||||
// if (Objects.isNull(appletPhoneInfo)) {
|
||||
// return AjaxResult.error("获取用户手机号失败");
|
||||
// }
|
||||
// if (Objects.nonNull(appletPhoneInfo.getErrcode()) && appletPhoneInfo.getErrcode() == ERROR_ACCESS_CODE) {
|
||||
// return AjaxResult.error("登录失败!");
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//if (StringUtils.isNotBlank(appletPhoneInfo.getErrmsg()) && !OK.equals(appletPhoneInfo.getErrmsg())) {
|
||||
// return AjaxResult.error("获取用户手机号失败,失败信息为:" + appletPhoneInfo.getErrmsg());
|
||||
//}
|
||||
// 根据手机号和openid判断当前用户是否存在
|
||||
//String phone = StringUtils.isBlank(appletPhoneInfo.getPhoneInfo().getPhoneNumber()) ? "" : appletPhoneInfo.getPhoneInfo().getPhoneNumber();
|
||||
String openId = StringUtils.isBlank(appletLoginInfo.getOpenid()) ? "" : appletLoginInfo.getOpenid();
|
||||
QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
|
||||
wrapper.lambda()
|
||||
//.eq(SysUser::getPhone, phone)
|
||||
.eq(SysUser::getOpenid, openId);
|
||||
SysUser userByPhone = sysUserService.getOne(wrapper, false);
|
||||
|
||||
SysUser user = new SysUser();
|
||||
// 考生信息为空,返回openId
|
||||
if (Objects.isNull(userByPhone)) {
|
||||
return AjaxResult.success("您还未注册,请注册后使用!", openId);
|
||||
}
|
||||
//更新用户的openid等微信标识信息
|
||||
user.setId(userByPhone.getId());
|
||||
user.setOpenid(openId);
|
||||
user.setPhone(StringUtils.isBlank(userByPhone.getPhone()) ? "" : userByPhone.getPhone());
|
||||
user.setUpdateTime(new Date());
|
||||
sysUserService.updateById(user);
|
||||
return AjaxResult.success(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据openid判断当前用户信息是否存在,微信小程序登录页使用
|
||||
*
|
||||
* @param openId 微信用户的openid
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult existUserInfo(String openId) {
|
||||
QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
|
||||
wrapper.lambda().eq(SysUser::getOpenid, openId);
|
||||
SysUser user = sysUserService.getOne(wrapper, false);
|
||||
if (Objects.nonNull(user) && StringUtils.isNotBlank(user.getOpenid())) {
|
||||
return AjaxResult.success("LOGIN");
|
||||
}
|
||||
return AjaxResult.success("NOT_LOGIN");
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.yf.exam.modules.applet.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description 微信小程序用户信息实体类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-08-17 16:12:22
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class AppletLoginVO implements Serializable {
|
||||
private static final long serialVersionUID = 3407837292456224369L;
|
||||
|
||||
/**
|
||||
* 小程序unionid
|
||||
*/
|
||||
private String unionid;
|
||||
|
||||
/**
|
||||
* 小程序openid
|
||||
*/
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* 错误状态码,40029:js_code无效,45011:API 调用太频繁,请稍候再试
|
||||
* 40226:高风险等级用户,小程序登录拦截 ,-1:系统繁忙,此时请开发者稍候再试
|
||||
*/
|
||||
private Integer errcode;
|
||||
|
||||
/**
|
||||
* 状态信息,取值有,40029:code 无效,
|
||||
* 45011:api minute-quota reach limit mustslower retry next minute
|
||||
* 40226:code blocked
|
||||
* -1:system error
|
||||
*/
|
||||
private String errmsg;
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
package com.yf.exam.modules.applet.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @Description 获取小程序用户手机号实体类
|
||||
* @Author 纪寒
|
||||
* @Date 2022-08-17 17:44:53
|
||||
* @Version 1.0
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class AppletPhoneVO implements Serializable {
|
||||
private static final long serialVersionUID = -135523900524315866L;
|
||||
|
||||
/**
|
||||
* 错误编码,
|
||||
* 0:成功
|
||||
* -1:系统繁忙,此时请开发者稍候再试
|
||||
* 40029:不合法的code(code不存在、已过期或者使用过)
|
||||
*/
|
||||
@JsonProperty("errcode")
|
||||
private Integer errcode;
|
||||
|
||||
/**
|
||||
* 返回提示信息,ok:成功
|
||||
*/
|
||||
@JsonProperty("errmsg")
|
||||
private String errmsg;
|
||||
|
||||
/**
|
||||
* 电话信息实体类
|
||||
*/
|
||||
@JsonProperty("phone_info")
|
||||
private PhoneInfoDTO phoneInfo;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class PhoneInfoDTO {
|
||||
|
||||
/**
|
||||
* 用户绑定的手机号(国外手机号会有区号)
|
||||
*/
|
||||
@JsonProperty("phoneNumber")
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 没有区号的手机号
|
||||
*/
|
||||
@JsonProperty("purePhoneNumber")
|
||||
private String purePhoneNumber;
|
||||
|
||||
/**
|
||||
* 区号
|
||||
*/
|
||||
@JsonProperty("countryCode")
|
||||
private Integer countryCode;
|
||||
|
||||
/**
|
||||
* 数据水印
|
||||
*/
|
||||
@JsonProperty("watermark")
|
||||
private WatermarkDTO watermark;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class WatermarkDTO {
|
||||
|
||||
/**
|
||||
* 用户获取手机号操作的时间戳
|
||||
*/
|
||||
@JsonProperty("timestamp")
|
||||
private Integer timestamp;
|
||||
|
||||
/**
|
||||
* 小程序appid
|
||||
*/
|
||||
@JsonProperty("appid")
|
||||
private String appid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,7 +55,7 @@ public class SysUserController extends BaseController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
* 用户退出
|
||||
* @return
|
||||
*/
|
||||
@CrossOrigin
|
||||
|
||||
@ -40,6 +40,9 @@ public class SysUserDTO extends UserAttachment implements Serializable {
|
||||
@ApiModelProperty(value = "密码盐", required=true)
|
||||
private String salt;
|
||||
|
||||
@ApiModelProperty(value = "用户微信openid", required=true)
|
||||
private String openid;
|
||||
|
||||
@ApiModelProperty(value = "角色列表", required=true)
|
||||
private String roleIds;
|
||||
|
||||
|
||||
@ -25,5 +25,8 @@ public class SysUserLoginReqDTO implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "密码", required=true)
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty(value = "用户微信openid", required=true)
|
||||
private String openid;
|
||||
|
||||
}
|
||||
|
||||
@ -35,6 +35,9 @@ public class SysUserLoginDTO extends UserAttachment implements Serializable {
|
||||
@ApiModelProperty(value = "手机号", required=true)
|
||||
private String phone;
|
||||
|
||||
@ApiModelProperty(value = "用户微信openid", required=true)
|
||||
private String openid;
|
||||
|
||||
@ApiModelProperty(value = "角色列表", required=true)
|
||||
private String roleIds;
|
||||
|
||||
|
||||
@ -68,6 +68,11 @@ public class SysUser extends UserAttachment {
|
||||
@TableField("depart_id")
|
||||
private String departId;
|
||||
|
||||
/**
|
||||
* 用户微信openid
|
||||
*/
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
|
||||
@ -142,8 +142,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
|
||||
@Override
|
||||
public void update(SysUserDTO reqDTO) {
|
||||
|
||||
|
||||
String pass = reqDTO.getPassword();
|
||||
if(!StringUtils.isBlank(pass)){
|
||||
PassInfo passInfo = PassHandler.buildPassword(pass);
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
package com.yf.exam.modules.utils;
|
||||
|
||||
import com.yf.exam.config.AppletChatConfig;
|
||||
import com.yf.exam.constant.Constants;
|
||||
import com.yf.exam.core.exception.ServiceException;
|
||||
import com.yf.exam.core.utils.AppletChatUtil;
|
||||
import com.yf.exam.modules.applet.entity.AppletAccessToken;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @Description 获取小程序AccessToken公共方法
|
||||
* @Author 纪寒
|
||||
* @Date 2023-02-27 18:02:05
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Component
|
||||
public class AppletAccessTokenUtil {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
@Resource
|
||||
private AppletChatConfig appletChatConfig;
|
||||
/**
|
||||
* 返回成功状态码
|
||||
*/
|
||||
private static final int SUCCESS_CODE = 0;
|
||||
|
||||
/**
|
||||
* 获取小程序AccessToken方法
|
||||
*
|
||||
* @return 小程序的AccessToken
|
||||
*/
|
||||
public String getAppletAccessToken() {
|
||||
String accessToken;
|
||||
String accessTokenKey = Constants.EXAM_APPLET_ACCESS_TOKEN + "accessToken";
|
||||
//从Redis中取出accessToken
|
||||
Object object = redisTemplate.opsForValue().get(accessTokenKey);
|
||||
if (Objects.isNull(object)) {
|
||||
//没有,获取accessToken
|
||||
AppletAccessToken appletAccessToken = AppletChatUtil.getAppletAccessToken(appletChatConfig.getAppletId(), appletChatConfig.getSecret());
|
||||
if (Objects.isNull(appletAccessToken)) {
|
||||
throw new ServiceException("获取微信小程序accessToken信息失败");
|
||||
}
|
||||
if (Objects.nonNull(appletAccessToken.getErrcode()) && appletAccessToken.getErrcode() != SUCCESS_CODE) {
|
||||
throw new ServiceException("获取微信小程序accessToken信息失败,失败信息为:" + appletAccessToken.getErrmsg());
|
||||
}
|
||||
if (StringUtils.isBlank(appletAccessToken.getAccessToken())) {
|
||||
throw new ServiceException("accessToken信息为空");
|
||||
}
|
||||
//存入Redis中
|
||||
redisTemplate.opsForValue().set(accessTokenKey, appletAccessToken.getAccessToken(), 3600, TimeUnit.SECONDS);
|
||||
accessToken = appletAccessToken.getAccessToken();
|
||||
} else {
|
||||
accessToken = (String) object;
|
||||
}
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
}
|
||||
28
exam-admin/src/main/resources/apiclient_key.pem
Normal file
28
exam-admin/src/main/resources/apiclient_key.pem
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQChOQsrP6xr7VpH
|
||||
LB6kMpx0wB9QXio6Fk89GwD1rFnR/8Eym6mUbv9BR7NddJ3LL1UCSQ3b1DXuDz64
|
||||
/s8nwvJmIABsgBmKS7Krb3qd7ua2NL7KodjnQuj4X3NOUQ2bPh21y5sOk6cVOObM
|
||||
4g2jvaPUk52y+kDXx/8IWLIms0hPqRkgCXVtTDrtgab4wABrfha3ifiC6qHuaeza
|
||||
ogo9he09QfWKPlZyW/OkwON4i0mMI0lAUaMnfSJX5QBLFwZYUHgR/8H/aMRLXnOx
|
||||
W/tz1bvV2SgKwpH7TalRu2Avl9t5M1lPWTbxl4vEV6em3ijqzldpIOljwJ20cL6g
|
||||
BbgJm2Y9AgMBAAECggEAOaVU2gTtWLXIZtRerGUwTgp359uTi6t4b6fdIvqaLx0c
|
||||
bkT8UIeTmzrQ5mSRGxp0cdm/K8/n7JPk4G6zkUsCMwPUQvdWqn1AiE3W8Ot/8LxR
|
||||
T9Co5p+k/1HZv7H5hH2kT+FaMs8Wmd77n1xgdiCTmKmjZGBYmQ74oHpeULof6+NA
|
||||
JX2LEMXBjSvcsEj2ppml1M9XjZzB7zPQPqVPGL5hTAqQpT179/iy8aPdzBZRKAFY
|
||||
liajWYlRVMseu1S21PaOygNpRhvLj+LQB+dfQ+s5jYIhBvVjJ4mNFK+ro1KrbFEa
|
||||
g2pKYFqcY9B4uOEB12K1bA4lxWPDjZvi5L71ncB8wQKBgQDTMDnOH+IQ/jrVbnX3
|
||||
YM24gKoJiKzbXcGSeg5jciGpAQ2JGtKw3xbZB54yXCwvJXssXkSfKmW9qKR299pG
|
||||
TloaKHbhHxvX1jECpFmvRTLEhKb6uWcy779NFv+443nM/G0cB+vxhezj4tqE6Qqw
|
||||
ijbDD+QS26Dm+ZfEQTaH1DaLbQKBgQDDbq8PEsL3uaoPg8gmyKJx9hmUW2nn3Tto
|
||||
CgOI7PVQbvwOIoI8phuc1VLatnxjx3SeMasGoWoVk7/hc0ZXHvo0QsQWZt74McSC
|
||||
mV2ub7L6BLyvrpsufEJZlUIiQXDIHDcucszgRaYJk4rJKmCh1R7c6dewAVE/TqTW
|
||||
7GrwUBI0EQKBgBRSFZ3Rz4zXCY4z3MH63JCeQL4+GnPZJ6ESgYPsHXUHlufUXuWJ
|
||||
8cbcRsqNt+qpbpqsT2oJSFThf0G7Q5N0QpM1xYqP1bwE7h5U9hQ5UlM6eF6zrExo
|
||||
aT3fsqd1q+ifeVgzIu7QdiTPVTtouRCXnAFU7BssauUOqx3FMJwNPVpZAoGAYMZ9
|
||||
j6RFwbBB4z7prTLrJi2sywddcUDfOwzCZVqZu8PJsyIphejngYktZzq4bByHxhJo
|
||||
U3c49ghdG0IfEeM4GQr62PEF9reGTPmvJ0MOyLnxyblYBPPpUz0TK61mMOGv/aNB
|
||||
islSiCl0r1r50QmdJ93wParZVdUW0YrvBaNQ8FECgYAm1j0tfGsMmocMYSoeMGt5
|
||||
wRetXbkrKfMbNh6GALiNClEj6tFYKMbuQOuUzADYDxHHz/SPNozuP7Ax/NI95rtw
|
||||
mGZcMx/KhKZQvZkAwCWUqRSn6cDPtqH4KNta7QZ8G36XtdPRP1a/h8g96cEiB/CV
|
||||
zQPps/kR9HNAJfr0sBPEWA==
|
||||
-----END PRIVATE KEY-----
|
||||
@ -28,20 +28,69 @@ server:
|
||||
enabled: true
|
||||
min-response-size: 10
|
||||
mime-types: application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
|
||||
|
||||
# 新医路微信商户号配置参数
|
||||
# redis 配置
|
||||
redis:
|
||||
# 地址
|
||||
host: localhost
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 2
|
||||
# 密码
|
||||
password:
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 8
|
||||
# 连接池的最大数据库连接数
|
||||
max-active: 8
|
||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
# 考试系统微信小程序参数配置信息
|
||||
exam-applet-chat-config:
|
||||
# 微信小程序
|
||||
applet-id: wx26b9ecdba54bc588
|
||||
# 微信小程序密钥
|
||||
secret: ccd19a0bb2bc74f38b083c902daf48a7
|
||||
# 微信小程序返回国家语言
|
||||
lang: zh_CN
|
||||
# 微信小程序授权类型
|
||||
grant-type: authorization_code
|
||||
# 微信小程序事件回调令牌
|
||||
token: Yw3vfW1ILpc34qAVDtTpB2hesAMCpvW0
|
||||
# 山东省公共卫生学会微信商户号配置参数
|
||||
xyl-we-chat-config:
|
||||
# 新医路商户号 1633348407 山东新医路信息科技有限公司 山东柏杏新医健康服务有限公司
|
||||
xyl-mch-id: 1690248007
|
||||
# 新医路商户号API证书序号 7C6A18FC8E1F0445901B1BE1C4DD1ACE284C3D79
|
||||
xyl-mch-serial-no: 760D3316C2F3DF8D1DB05B56A37BFCD3C34EEDA8
|
||||
# 新医路商户私钥文件
|
||||
xyl-private-key-path: baixing_apiclient_key.pem
|
||||
# 新医路API V3版本密钥 Xyl699003981qazVFR4xsw23edcASDFG
|
||||
xyl-payment-key: baixingXINYIHULIZHAN202400000000
|
||||
# 新医路微信支付回调地址 https://quanyidaojia.xinelu.cn
|
||||
# 山东省公共卫生学会商户号 1724506668 山东省公共卫生学会
|
||||
xyl-mch-id: 1724506668
|
||||
# 山东省公共卫生学会商户号API证书序号 2C1188B1E533743F24AA43D374118B5D4A4FABC1
|
||||
xyl-mch-serial-no: 2C1188B1E533743F24AA43D374118B5D4A4FABC1
|
||||
# 山东省公共卫生学会商户私钥文件
|
||||
xyl-private-key-path: apiclient_key.pem
|
||||
# 山东省公共卫生学会API V3版本密钥 Xyl699003981qazVFR4xsw23edcASDFG
|
||||
xyl-payment-key: gonggongweishengXUEHUI2025081100
|
||||
# 山东省公共卫生学会微信支付回调地址 https://quanyidaojia.xinelu.cn
|
||||
xyl-wechat-notify-url: http://8.131.93.145:54097
|
||||
# h5支付接口地址
|
||||
# 微信支付接口地址,包含小程序和App支付接口地址
|
||||
we-chat-payment-url-config:
|
||||
# h5下单接口地址
|
||||
h5-palce-order-url: https://api.mch.weixin.qq.com/v3/pay/transactions/h5
|
||||
# 小程序JSAPI下单接口地址
|
||||
jsapi-palce-order-url: https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
|
||||
# 微信支付订单号查询接口地址
|
||||
query-order-no-url: https://api.mch.weixin.qq.com/v3/pay/transactions/id/%s
|
||||
# 商户订单号接口查询
|
||||
query-mch-id-url: https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s
|
||||
# 关闭订单接口地址
|
||||
close-order-url: https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s/close
|
||||
# 申请退款接口地址
|
||||
refund-apply-url: https://api.mch.weixin.qq.com/v3/refund/domestic/refunds
|
||||
# 查询单笔退款接口地址
|
||||
refund-query-order-url: https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/%s
|
||||
# 申请交易账单接口地址
|
||||
trade-apply-bill-url: https://api.mch.weixin.qq.com/v3/bill/tradebill
|
||||
# 申请资金账单接口地址
|
||||
capital-apply-bill-url: https://api.mch.weixin.qq.com/v3/bill/fundflowbill
|
||||
# App下单接口地址
|
||||
app-place-order-url: https://api.mch.weixin.qq.com/v3/pay/transactions/app
|
||||
|
||||
@ -29,13 +29,14 @@
|
||||
<result column="photo" property="photo" />
|
||||
<result column="certificate" property="certificate" />
|
||||
<result column="physical_report" property="physicalReport" />
|
||||
<result column="openid" property="openid" />
|
||||
</resultMap>
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
`id`,`user_name`,`real_name`,phone,`password`,`salt`,`role_ids`,`depart_id`,`create_time`,`update_time`,`state`,
|
||||
`email`,`address`,`education`,`graduate_school`,`major`,`reg_type`,`train_institution`,`train_start_date`,`train_end_date`,
|
||||
`card_front`,`card_back`,`card_copy`,`photo`,`certificate`,`physical_report`
|
||||
`card_front`,`card_back`,`card_copy`,`photo`,`certificate`,`physical_report`,`openid`
|
||||
|
||||
</sql>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user