2024-02-26 朱宝民 解决添加用户主键不自动创建的问题,部分微信支付代码
| | |
| | | package com.dy.common.mybatis; |
| | | |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.alibaba.fastjson2.JSONWriter; |
| | | import com.dy.common.po.BaseEntity; |
| | | import com.dy.common.util.IDLongGenerator; |
| | | import org.apache.ibatis.executor.Executor; |
| | | import org.apache.ibatis.mapping.MappedStatement; |
| | | import org.apache.ibatis.mapping.SqlCommandType; |
| | | import org.apache.ibatis.plugin.Interceptor; |
| | | import org.apache.ibatis.plugin.Intercepts; |
| | | import org.apache.ibatis.plugin.Invocation; |
| | | import org.apache.ibatis.plugin.Plugin; |
| | | import org.apache.ibatis.plugin.Signature; |
| | | import org.apache.ibatis.plugin.*; |
| | | |
| | | import java.lang.reflect.Method; |
| | | |
| | |
| | | static int MAPPED_STATEMENT_INDEX = 0; |
| | | static int PARAMETER_INDEX = 1; |
| | | static String BASE_FIELD_SET_PRIMARY_KEY_FUNTION_NAME = "setId"; |
| | | static String BASE_FIELD_SET_PRIMARY_KEY_FUNTION_NAME2 = "setUserId"; |
| | | |
| | | /** |
| | | * 拦截逻辑实现 |
| | |
| | | Class<?> entityClass = entity.getClass(); |
| | | Method setMt = null ; |
| | | try{ |
| | | // 判断主键是id还是userId |
| | | String jsonString = JSONObject.toJSONString(entity, JSONWriter.Feature.WriteMapNullValue); |
| | | JSONObject jsonObject = JSONObject.parseObject(jsonString); |
| | | if(jsonObject.containsKey("userId")) { |
| | | setMt = entityClass.getMethod(BASE_FIELD_SET_PRIMARY_KEY_FUNTION_NAME2, Long.class) ; |
| | | }else { |
| | | //有一些实体没有id,例如中间表 |
| | | setMt = entityClass.getMethod(BASE_FIELD_SET_PRIMARY_KEY_FUNTION_NAME, Long.class) ; |
| | | } |
| | | }catch (Exception e){ |
| | | //当entityClass没有setId方法时,会抛出异常 |
| | | } |
New file |
| | |
| | | package com.dy.pipIrrGlobal.daoSe; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.dy.pipIrrGlobal.pojoSe.SeWebchatLogonState; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | /** |
| | | * @author ZhuBaoMin |
| | | * @date 2024-02-22 17:31 |
| | | * @LastEditTime 2024-02-22 17:31 |
| | | * @Description |
| | | */ |
| | | |
| | | @Mapper |
| | | public interface SeWebchatLogonStateMapper extends BaseMapper<SeWebchatLogonState> { |
| | | int deleteByPrimaryKey(Long id); |
| | | |
| | | int insert(SeWebchatLogonState record); |
| | | |
| | | int insertSelective(SeWebchatLogonState record); |
| | | |
| | | SeWebchatLogonState selectByPrimaryKey(Long id); |
| | | |
| | | int updateByPrimaryKeySelective(SeWebchatLogonState record); |
| | | |
| | | int updateByPrimaryKey(SeWebchatLogonState record); |
| | | } |
New file |
| | |
| | | package com.dy.pipIrrGlobal.pojoSe; |
| | | |
| | | import com.alibaba.fastjson2.annotation.JSONField; |
| | | import com.alibaba.fastjson2.writer.ObjectWriterImplToString; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.dy.common.po.BaseEntity; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import lombok.*; |
| | | |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * @author ZhuBaoMin |
| | | * @date 2024-02-22 17:31 |
| | | * @LastEditTime 2024-02-22 17:31 |
| | | * @Description |
| | | */ |
| | | |
| | | @TableName(value="se_webchat_logon_state", autoResultMap = true) |
| | | @Data |
| | | @Builder |
| | | @ToString |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | @Schema(name = "登录态记录实体") |
| | | public class SeWebchatLogonState implements BaseEntity { |
| | | public static final long serialVersionUID = 202402221735001L; |
| | | |
| | | /** |
| | | * 主键 |
| | | */ |
| | | @JSONField(serializeUsing= ObjectWriterImplToString.class) |
| | | @TableId(type = IdType.INPUT) |
| | | @Schema(description = "实体id", requiredMode = Schema.RequiredMode.NOT_REQUIRED) |
| | | private Long id; |
| | | |
| | | /** |
| | | * 用户唯一标识 |
| | | */ |
| | | @Schema(description = "用户唯一标识", requiredMode = Schema.RequiredMode.NOT_REQUIRED) |
| | | @NotBlank(message = "用户唯一标识不能为空") |
| | | private String openId; |
| | | |
| | | /** |
| | | * 会话密钥 |
| | | */ |
| | | @Schema(description = "会话密钥", requiredMode = Schema.RequiredMode.NOT_REQUIRED) |
| | | @NotBlank(message = "会话密钥不能为空") |
| | | private String sessionKey; |
| | | |
| | | /** |
| | | * 创建时间 |
| | | */ |
| | | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.NOT_REQUIRED) |
| | | @NotBlank(message = "创建时间不能为空") |
| | | private Date createTime; |
| | | } |
New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| | | <mapper namespace="com.dy.pipIrrGlobal.daoSe.SeWebchatLogonStateMapper"> |
| | | <resultMap id="BaseResultMap" type="com.dy.pipIrrGlobal.pojoSe.SeWebchatLogonState"> |
| | | <!--@mbg.generated--> |
| | | <!--@Table se_webchat_logon_state--> |
| | | <id column="id" jdbcType="BIGINT" property="id" /> |
| | | <result column="open_id" jdbcType="VARCHAR" property="openId" /> |
| | | <result column="session_key" jdbcType="VARCHAR" property="sessionKey" /> |
| | | <result column="create_time" jdbcType="TIMESTAMP" property="createTime" /> |
| | | </resultMap> |
| | | <sql id="Base_Column_List"> |
| | | <!--@mbg.generated--> |
| | | id, open_id, session_key, create_time |
| | | </sql> |
| | | <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap"> |
| | | <!--@mbg.generated--> |
| | | select |
| | | <include refid="Base_Column_List" /> |
| | | from se_webchat_logon_state |
| | | where id = #{id,jdbcType=BIGINT} |
| | | </select> |
| | | <delete id="deleteByPrimaryKey" parameterType="java.lang.Long"> |
| | | <!--@mbg.generated--> |
| | | delete from se_webchat_logon_state |
| | | where id = #{id,jdbcType=BIGINT} |
| | | </delete> |
| | | <insert id="insert" parameterType="com.dy.pipIrrGlobal.pojoSe.SeWebchatLogonState"> |
| | | <!--@mbg.generated--> |
| | | insert into se_webchat_logon_state (id, open_id, session_key, |
| | | create_time) |
| | | values (#{id,jdbcType=BIGINT}, #{openId,jdbcType=VARCHAR}, #{sessionKey,jdbcType=VARCHAR}, |
| | | #{createTime,jdbcType=TIMESTAMP}) |
| | | </insert> |
| | | <insert id="insertSelective" parameterType="com.dy.pipIrrGlobal.pojoSe.SeWebchatLogonState"> |
| | | <!--@mbg.generated--> |
| | | insert into se_webchat_logon_state |
| | | <trim prefix="(" suffix=")" suffixOverrides=","> |
| | | <if test="id != null"> |
| | | id, |
| | | </if> |
| | | <if test="openId != null"> |
| | | open_id, |
| | | </if> |
| | | <if test="sessionKey != null"> |
| | | session_key, |
| | | </if> |
| | | <if test="createTime != null"> |
| | | create_time, |
| | | </if> |
| | | </trim> |
| | | <trim prefix="values (" suffix=")" suffixOverrides=","> |
| | | <if test="id != null"> |
| | | #{id,jdbcType=BIGINT}, |
| | | </if> |
| | | <if test="openId != null"> |
| | | #{openId,jdbcType=VARCHAR}, |
| | | </if> |
| | | <if test="sessionKey != null"> |
| | | #{sessionKey,jdbcType=VARCHAR}, |
| | | </if> |
| | | <if test="createTime != null"> |
| | | #{createTime,jdbcType=TIMESTAMP}, |
| | | </if> |
| | | </trim> |
| | | </insert> |
| | | <update id="updateByPrimaryKeySelective" parameterType="com.dy.pipIrrGlobal.pojoSe.SeWebchatLogonState"> |
| | | <!--@mbg.generated--> |
| | | update se_webchat_logon_state |
| | | <set> |
| | | <if test="openId != null"> |
| | | open_id = #{openId,jdbcType=VARCHAR}, |
| | | </if> |
| | | <if test="sessionKey != null"> |
| | | session_key = #{sessionKey,jdbcType=VARCHAR}, |
| | | </if> |
| | | <if test="createTime != null"> |
| | | create_time = #{createTime,jdbcType=TIMESTAMP}, |
| | | </if> |
| | | </set> |
| | | where id = #{id,jdbcType=BIGINT} |
| | | </update> |
| | | <update id="updateByPrimaryKey" parameterType="com.dy.pipIrrGlobal.pojoSe.SeWebchatLogonState"> |
| | | <!--@mbg.generated--> |
| | | update se_webchat_logon_state |
| | | set open_id = #{openId,jdbcType=VARCHAR}, |
| | | session_key = #{sessionKey,jdbcType=VARCHAR}, |
| | | create_time = #{createTime,jdbcType=TIMESTAMP} |
| | | where id = #{id,jdbcType=BIGINT} |
| | | </update> |
| | | </mapper> |
| | |
| | | <name>pipIrr-web-webchat</name> |
| | | <description>web微信支付模块</description> |
| | | |
| | | <dependencies> |
| | | <!--微信支付--> |
| | | <dependency> |
| | | <groupId>com.github.wechatpay-apiv3</groupId> |
| | | <artifactId>wechatpay-java</artifactId> |
| | | <version>0.2.12</version> |
| | | </dependency> |
| | | |
| | | <!--OkHttp--> |
| | | <dependency> |
| | | <groupId>com.squareup.okhttp3</groupId> |
| | | <artifactId>okhttp</artifactId> |
| | | <version>4.9.2</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>org.apache.httpcomponents</groupId> |
| | | <artifactId>httpclient</artifactId> |
| | | <version>4.5.3</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>org.apache.httpcomponents.client5</groupId> |
| | | <artifactId>httpclient5</artifactId> |
| | | <version>5.1.3</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.httpcomponents.client5</groupId> |
| | | <artifactId>httpclient5-fluent</artifactId> |
| | | <version>5.1.3</version> |
| | | </dependency> |
| | | |
| | | </dependencies> |
| | | <build> |
| | | <plugins> |
| | | <!-- 生成不包含依赖jar的可执行jar包 |
| | |
| | | @EnableAspectJAutoProxy |
| | | @EnableMultiDataSource |
| | | @ComponentScan(basePackages = {"com.dy.common", "com.dy.pipIrrGlobal", "com.dy.pipirrWebChat"}) |
| | | @MapperScan({"com.dy.pipIrrGlobal.daoPr", "com.dy.pipIrrGlobal.daoBa"}) |
| | | @MapperScan({"com.dy.pipIrrGlobal.daoSe", "com.dy.pipIrrGlobal.daoBa"}) |
| | | public class PipIrrWebChatApplication { |
| | | |
| | | public static void main(String[] args) { |
New file |
| | |
| | | package com.dy.pipirrWebChat.config; |
| | | |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.http.converter.HttpMessageConverter; |
| | | import org.springframework.http.converter.StringHttpMessageConverter; |
| | | import org.springframework.web.client.RestTemplate; |
| | | |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.util.List; |
| | | //import org.apache.http.client.HttpClient; |
| | | |
| | | /** |
| | | * @author ZhuBaoMin |
| | | * @date 2024-02-23 15:42 |
| | | * @LastEditTime 2024-02-23 15:42 |
| | | * @Description |
| | | */ |
| | | |
| | | @Configuration |
| | | public class RestTemplateConfig { |
| | | @Autowired |
| | | private RestTemplateWechatCertConfig restTemplateWechatCertConfig; |
| | | |
| | | //@Bean |
| | | //public RestTemplate restTemplate() { |
| | | // return new RestTemplate(); |
| | | //} |
| | | |
| | | //@Bean |
| | | //public RestTemplate restTemplate() { |
| | | // String mchid = PayInfo.mchid; |
| | | // RestTemplate restTemplate = null; |
| | | // try { |
| | | // KeyStore keyStore = KeyStore.getInstance("PKCS12"); |
| | | // //InputStream cp = this.getClass().getResourceAsStream("apiclient_cert.p12"); |
| | | // FileInputStream instream = new FileInputStream(new File("C:\\webchat\\apiclient_cert.p12")); |
| | | // keyStore.load(instream, mchid.toCharArray()); |
| | | // // Trust own CA and all self-signed certs |
| | | // SSLContext sslcontext = SSLContextBuilder.create() |
| | | // .loadKeyMaterial(keyStore, mchid.toCharArray()) |
| | | // .build(); |
| | | // //Allow TLSv1 protocol only |
| | | // SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, NoopHostnameVerifier.INSTANCE); |
| | | // CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); |
| | | // HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); |
| | | // |
| | | // restTemplate = new RestTemplate(factory); |
| | | // //将转换器的编码换成utf-8 |
| | | // restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("utf-8"))); |
| | | // //System.out.println("restTemplate.hashCode():" + restTemplate.hashCode()); |
| | | // } catch (Exception e) { |
| | | // e.printStackTrace(); |
| | | // } |
| | | // return restTemplate; |
| | | //} |
| | | |
| | | //@Bean(name = "wechatRestTemplate") |
| | | @Bean() |
| | | public RestTemplate restTemplate() throws Exception { |
| | | RestTemplate restTemplate = new RestTemplate(restTemplateWechatCertConfig.wechatHttpRequestFactory()); |
| | | // 添加拦截器 |
| | | //List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>(); |
| | | //RestTemplateWechatCertConfig.MyRequestInterceptor myRequestInterceptor = new RestTemplateWechatCertConfig.MyRequestInterceptor(); |
| | | //interceptors.add(myRequestInterceptor); |
| | | //restTemplate.setInterceptors(interceptors); |
| | | |
| | | // 中文乱码,主要是 StringHttpMessageConverter的默认编码为ISO导致的 |
| | | List<HttpMessageConverter<?>> list = restTemplate.getMessageConverters(); |
| | | for (HttpMessageConverter converter : list) { |
| | | if (converter instanceof StringHttpMessageConverter) { |
| | | ((StringHttpMessageConverter) converter).setDefaultCharset(StandardCharsets.UTF_8); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return restTemplate; |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | package com.dy.pipirrWebChat.config; |
| | | |
| | | import com.dy.pipirrWebChat.payment.PayInfo; |
| | | import okhttp3.OkHttpClient; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.http.client.ClientHttpRequestFactory; |
| | | import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; |
| | | |
| | | import javax.net.ssl.KeyManagerFactory; |
| | | import javax.net.ssl.SSLContext; |
| | | import javax.net.ssl.TrustManagerFactory; |
| | | import javax.net.ssl.X509TrustManager; |
| | | import java.io.File; |
| | | import java.io.FileInputStream; |
| | | import java.security.KeyStore; |
| | | |
| | | /** |
| | | * @author ZhuBaoMin |
| | | * @date 2024-02-23 19:18 |
| | | * @LastEditTime 2024-02-23 19:18 |
| | | * @Description |
| | | */ |
| | | |
| | | @Configuration |
| | | public class RestTemplateWechatCertConfig { |
| | | String mchid = PayInfo.mchid; |
| | | |
| | | @Bean |
| | | @ConfigurationProperties(prefix = "org.liurb.core.rest-template.config.connection") |
| | | public ClientHttpRequestFactory wechatHttpRequestFactory() throws Exception { |
| | | |
| | | KeyStore keyStore = KeyStore.getInstance("PKCS12"); |
| | | //InputStream cp = this.getClass().getResourceAsStream("apiclient_cert.p12"); |
| | | FileInputStream instream = new FileInputStream(new File("C:\\webchat\\apiclient_cert.p12")); |
| | | keyStore.load(instream, mchid.toCharArray()); |
| | | |
| | | KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); |
| | | keyManagerFactory.init(keyStore, mchid.toCharArray()); |
| | | |
| | | SSLContext context = SSLContext.getInstance("TLS"); |
| | | context.init(keyManagerFactory.getKeyManagers(), null, null); |
| | | |
| | | OkHttpClient okHttpClient = new OkHttpClient.Builder() |
| | | .sslSocketFactory(context.getSocketFactory(), getDefaultX509TrustManager()) |
| | | .build(); |
| | | |
| | | return new OkHttp3ClientHttpRequestFactory(okHttpClient); |
| | | } |
| | | |
| | | private static X509TrustManager getDefaultX509TrustManager() throws Exception { |
| | | TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); |
| | | factory.init((KeyStore) null); |
| | | return (X509TrustManager) factory.getTrustManagers()[0]; |
| | | } |
| | | } |
New file |
| | |
| | | package com.dy.pipirrWebChat.payment; |
| | | |
| | | import javax.crypto.NoSuchPaddingException; |
| | | import java.io.IOException; |
| | | import java.nio.file.Files; |
| | | import java.nio.file.Paths; |
| | | import java.security.*; |
| | | import java.security.spec.InvalidKeySpecException; |
| | | import java.security.spec.PKCS8EncodedKeySpec; |
| | | import java.util.Base64; |
| | | import java.util.Random; |
| | | |
| | | /** |
| | | * @author ZhuBaoMin |
| | | * @date 2024-02-22 20:31 |
| | | * @LastEditTime 2024-02-22 20:31 |
| | | * @Description |
| | | */ |
| | | public class PayHelper { |
| | | private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; |
| | | |
| | | /** |
| | | * 获取32位随机字符串 |
| | | * @return 随机串 |
| | | */ |
| | | public static String generateRandomString() { |
| | | Random random = new Random(); |
| | | StringBuilder sb = new StringBuilder(32); |
| | | for (int i = 0; i < 32; i++) { |
| | | int index = random.nextInt(CHARACTERS.length()); |
| | | sb.append(CHARACTERS.charAt(index)); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 获取私钥对象 |
| | | * @param filename 私钥文件路径 |
| | | * @return 私钥对象 |
| | | * @throws IOException |
| | | */ |
| | | public static PrivateKey getPrivateKey(String filename) throws IOException { |
| | | //String filename = "C:\\webchat\\apiclient_key.pem"; |
| | | String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8"); |
| | | try { |
| | | String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "") |
| | | .replace("-----END PRIVATE KEY-----", "") |
| | | .replaceAll("\\s+", ""); |
| | | KeyFactory kf = KeyFactory.getInstance("RSA"); |
| | | return kf.generatePrivate( |
| | | new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey))); |
| | | } catch (NoSuchAlgorithmException e) { |
| | | throw new RuntimeException("当前Java环境不支持RSA", e); |
| | | } catch (InvalidKeySpecException e) { |
| | | throw new RuntimeException("无效的密钥格式"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 构造签名串_下单 |
| | | * @param method HTTP请求方法 |
| | | * @param url URL |
| | | * @param timestamp 时间戳 |
| | | * @param nonceStr 随机串 |
| | | * @param body 报文主题 |
| | | * @return 签名串 |
| | | */ |
| | | public static String buildMessage_order(String method, String url, long timestamp, String nonceStr, String body) { |
| | | return method + "\n" |
| | | + url + "\n" |
| | | + timestamp + "\n" |
| | | + nonceStr + "\n" |
| | | + body + "\n"; |
| | | } |
| | | |
| | | public static String buildMessage_signAgain(String appid, String timestamp, String nonceStr, String pkg) { |
| | | return appid + "\n" |
| | | + timestamp + "\n" |
| | | + nonceStr + "\n" |
| | | + pkg + "\n"; |
| | | } |
| | | |
| | | /** |
| | | * 签名 |
| | | * @param message 被签名信息 |
| | | * @param certFileName 私钥证书文件路径 |
| | | * @return signature签名值,签名信息中的一项,参与生成签名信息 |
| | | * @throws NoSuchAlgorithmException |
| | | * @throws InvalidKeyException |
| | | * @throws SignatureException |
| | | * @throws IOException |
| | | */ |
| | | public static String sign(byte[] message, String certFileName) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, IOException { |
| | | Signature sign = Signature.getInstance("SHA256withRSA"); |
| | | sign.initSign(getPrivateKey(certFileName)); |
| | | sign.update(message); |
| | | return Base64.getEncoder().encodeToString(sign.sign()); |
| | | } |
| | | |
| | | /** |
| | | * 获取签名信息 |
| | | * @param method |
| | | * @param url |
| | | * @param body |
| | | * @return 签名信息,HTTP头中的签名信息 |
| | | * HTTP头:Authorization: 认证类型 签名信息 |
| | | * 认证类型,WECHATPAY2-SHA256-RSA2048 |
| | | */ |
| | | public static String getToken(String method, String url, String body, String nonceStr, Long timestamp, String certFileName) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException, NoSuchPaddingException { |
| | | String message = buildMessage_order(method, url, timestamp, nonceStr, body); |
| | | String signature = sign(message.getBytes("utf-8"), certFileName); |
| | | |
| | | return "mchid=\"" + PayInfo.mchid + "\"," |
| | | + "nonce_str=\"" + nonceStr + "\"," |
| | | + "timestamp=\"" + timestamp + "\"," |
| | | + "serial_no=\"" + PayInfo.serial_no + "\"," |
| | | + "signature=\"" + signature + "\""; |
| | | } |
| | | } |
New file |
| | |
| | | package com.dy.pipirrWebChat.payment; |
| | | |
| | | /** |
| | | * @author ZhuBaoMin |
| | | * @date 2024-02-22 20:20 |
| | | * @LastEditTime 2024-02-22 20:20 |
| | | * @Description |
| | | */ |
| | | public class PayInfo { |
| | | /* |
| | | * 小程序登录API |
| | | */ |
| | | public static String loginUrl = "https://api.weixin.qq.com/sns/jscode2session"; |
| | | |
| | | /* |
| | | * 统一下单API |
| | | */ |
| | | //public static String orderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder"; |
| | | public static String orderUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"; |
| | | |
| | | /** |
| | | * 平台证书下载URL |
| | | */ |
| | | public static String certificates = "https://api.mch.weixin.qq.com/v3/certificates"; |
| | | |
| | | /* |
| | | * 支付结果通知API |
| | | */ |
| | | public static String notifyUrl = "https://www.muxiaobao.com/api/Payment/OrderNotify"; |
| | | |
| | | /* |
| | | * 查询订单API |
| | | */ |
| | | public static String queryUrl = "https://api.mch.weixin.qq.com/pay/orderquery"; |
| | | |
| | | /* |
| | | * 申请退款API |
| | | */ |
| | | public static String refundUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund"; |
| | | |
| | | /* |
| | | * 退款通知API |
| | | */ |
| | | public static String refundNotifyUrl = "https://www.muxiaobao.com/wxpay/pay.action"; |
| | | |
| | | /* |
| | | * 退款查询API |
| | | */ |
| | | public static String refundQueryUrl = "https://api.mch.weixin.qq.com/pay/refundquery"; |
| | | |
| | | /* |
| | | * 小程序唯一标识 |
| | | */ |
| | | public static String appid = "wxf776aebf73f34962"; |
| | | |
| | | /* |
| | | * 小程序的 app secret |
| | | */ |
| | | public static String secret = "b05862b7fa8a944114dbe970c2764ae6"; |
| | | |
| | | /* |
| | | * 小程序的授权类型,登录凭证校验使用 |
| | | */ |
| | | public static String grantType = "authorization_code"; |
| | | |
| | | /* |
| | | * 商户号(微信支付分配的商户号) |
| | | */ |
| | | public static String mchid = "1640721520"; |
| | | |
| | | /* |
| | | * 商户平台设置的密钥key |
| | | */ |
| | | public static String key = "DaYuJieShuiYanJiuYuan20230412ABC"; |
| | | |
| | | /** |
| | | * 商户API证书序列号 |
| | | */ |
| | | public static String serial_no = "52D65AA66405C738670377F467178F4C950E1606"; |
| | | |
| | | /* |
| | | * 终端IP,调用微信支付API的机器IP |
| | | */ |
| | | public static String addrIp = "47.104.211.89"; |
| | | |
| | | /* |
| | | * 随机字符串,长度要求在32位以内 |
| | | */ |
| | | //public static String nonceStr = PayHelper.generateRandomString(); |
| | | |
| | | /* |
| | | * 时间戳 从1970年1月1日00:00:00至今的秒数,即当前的时间 |
| | | */ |
| | | //public static Long timeStamp = PayHelper.getTimeStamp(); |
| | | |
| | | /* |
| | | * 交易类型,小程序取值JSAPI |
| | | */ |
| | | public static String tradeType = "JSAPI"; |
| | | |
| | | /* |
| | | * 签名类型 |
| | | */ |
| | | //public static String signType = "MD5"; |
| | | public static String signType = "RSA"; |
| | | |
| | | /* |
| | | * 商品描述 商品简单描述,该字段请按照规范传递 |
| | | */ |
| | | //public static String body = "大禹研究院-水费"; |
| | | public static String description = "大禹研究院-水费"; |
| | | |
| | | /* |
| | | * 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用 |
| | | */ |
| | | public static String attach = "天津"; |
| | | |
| | | /* |
| | | * 签名,参与签名参数:appid、attach、mch_id、nonce_str、body、out_trade_no、total_fee、spbill_create_ip、notify_url、trade_type、openid |
| | | */ |
| | | public String sign = ""; |
| | | |
| | | /** |
| | | * HTTP头认证类型 |
| | | */ |
| | | public static String schema = "WECHATPAY2-SHA256-RSA2048"; |
| | | |
| | | /** |
| | | * 私钥文件路径 |
| | | */ |
| | | public static String certFileName = "C:\\webchat\\apiclient_key.pem"; |
| | | |
| | | /* |
| | | * 微信订单号,优先使用 |
| | | */ |
| | | public static String transactionid = ""; |
| | | |
| | | /* |
| | | * 商户系统内部订单号 |
| | | */ |
| | | public static String out_trade_no = ""; |
| | | |
| | | /* |
| | | * 商户退款单号 |
| | | */ |
| | | public static String out_refund_no = ""; |
| | | |
| | | /* |
| | | * 退款金额 |
| | | */ |
| | | public static Float refundfee; |
| | | |
| | | /* |
| | | * 订单金额 |
| | | */ |
| | | public static Float totalfee; |
| | | } |
New file |
| | |
| | | package com.dy.pipirrWebChat.payment; |
| | | |
| | | import com.alibaba.fastjson2.JSONArray; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.dy.common.aop.SsoAop; |
| | | import com.dy.common.webUtil.BaseResponse; |
| | | import com.dy.common.webUtil.BaseResponseUtils; |
| | | import com.dy.common.webUtil.ResultCodeMsg; |
| | | import com.dy.pipIrrGlobal.pojoSe.SeWebchatLogonState; |
| | | import com.dy.pipirrWebChat.util.OkHttpUtil; |
| | | import com.dy.pipirrWebChat.util.RestTemplateUtil; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.media.Content; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import io.swagger.v3.oas.annotations.responses.ApiResponse; |
| | | import io.swagger.v3.oas.annotations.responses.ApiResponses; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * @author ZhuBaoMin |
| | | * @date 2024-02-22 15:24 |
| | | * @LastEditTime 2024-02-22 15:24 |
| | | * @Description |
| | | */ |
| | | |
| | | @Slf4j |
| | | @Tag(name = "微信支付管理", description = "微信支付各种操作") |
| | | @RestController |
| | | @RequestMapping(path="payment") |
| | | @RequiredArgsConstructor |
| | | public class PaymentCtrl { |
| | | private final PaymentSv paymentSv; |
| | | private final RestTemplateUtil restTemplateUtil; |
| | | private String certFileName = PayInfo.certFileName; |
| | | |
| | | /** |
| | | * 登录凭证校验 |
| | | * @param appid 小程序 appId |
| | | * @param secret 小程序 appSecret |
| | | * @param js_code 临时登录凭证code |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | @Operation(summary = "登录凭证校验", description = "登录凭证校验") |
| | | @ApiResponses(value = { |
| | | @ApiResponse( |
| | | responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE, |
| | | description = "操作结果:true:成功,false:失败(BaseResponse.content)", |
| | | content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, |
| | | schema = @Schema(implementation = Boolean.class))} |
| | | ) |
| | | }) |
| | | @PostMapping(path = "getSessionId") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @SsoAop() |
| | | public BaseResponse<Boolean> getSessionId(@RequestParam("appid") String appid, @RequestParam("secret") String secret, @RequestParam("js_code") String js_code) throws Exception { |
| | | String result = OkHttpUtil.builder().url("https://api.weixin.qq.com/sns/jscode2session") |
| | | .addParam("appid", appid) |
| | | .addParam("secret", secret) |
| | | .addParam("js_code", js_code) |
| | | .initGet() |
| | | .sync(); |
| | | JSONObject job = JSONObject.parseObject(result); |
| | | System.out.println(job.getString("session_key")); |
| | | |
| | | if(job.getLong("errcode") != null && job.getLong("errcode") >= -1) { |
| | | return BaseResponseUtils.buildFail("登录凭证校验失败"); |
| | | } |
| | | |
| | | // 添加登录态记录 |
| | | SeWebchatLogonState po = new SeWebchatLogonState(); |
| | | po.setOpenId(job.getString("openid")); |
| | | po.setSessionKey(job.getString("session_key")); |
| | | Date createTime = new Date(); |
| | | po.setCreateTime(createTime); |
| | | Long id = paymentSv.insert(po); |
| | | if(id == null || id <= 0) { |
| | | return BaseResponseUtils.buildFail("登录态记录添加失败"); |
| | | } |
| | | |
| | | String SessionId = String.valueOf(id); |
| | | return BaseResponseUtils.buildSuccess(SessionId) ; |
| | | } |
| | | |
| | | @Operation(summary = "下载平台证书", description = "下载平台证书") |
| | | @ApiResponses(value = { |
| | | @ApiResponse( |
| | | responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE, |
| | | description = "操作结果:true:成功,false:失败(BaseResponse.content)", |
| | | content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, |
| | | schema = @Schema(implementation = Boolean.class))} |
| | | ) |
| | | }) |
| | | @GetMapping(path = "certificates") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @SsoAop() |
| | | public BaseResponse<JSONObject> certificates() throws Exception { |
| | | //String prepayId = ""; |
| | | //SeWebchatLogonState po = paymentSv.selectOne(Long.parseLong(sessionId)); |
| | | //String openid = po.getOpenId(); |
| | | |
| | | String method = "GET"; |
| | | String httpUrl = "/v3/certificates"; |
| | | String nonceStr = PayHelper.generateRandomString(); |
| | | Long timestamp = System.currentTimeMillis() / 1000; |
| | | |
| | | String header = PayInfo.schema + " " + PayHelper.getToken(method, httpUrl, "", nonceStr, timestamp, certFileName); |
| | | |
| | | Map<String, String> headers = new HashMap<>(); |
| | | headers.put("Authorization", header); |
| | | headers.put("Accept", "application/json"); |
| | | JSONObject job_result = restTemplateUtil.get(PayInfo.certificates,null, headers); |
| | | if(job_result != null) { |
| | | JSONArray array = job_result.getJSONArray("data"); |
| | | if(array != null && array.size() > 0) { |
| | | for(int i = 0; i < array.size(); i++) { |
| | | JSONObject job_data = array.getJSONObject(i); |
| | | String serial_no = job_data.getString("serial_no"); |
| | | String effective_time = job_data.getString("effective_time"); |
| | | String expire_time = job_data.getString("expire_time"); |
| | | JSONObject job_certificate = job_data.getJSONObject("encrypt_certificate"); |
| | | String algorithm = job_certificate.getString("algorithm"); |
| | | String nonce = job_certificate.getString("nonce"); |
| | | String associated_data = job_certificate.getString("associated_data"); |
| | | String ciphertext = job_certificate.getString("ciphertext"); |
| | | } |
| | | } |
| | | } |
| | | System.out.println(job_result.toJSONString()); |
| | | return BaseResponseUtils.buildSuccess(job_result.toJSONString()) ; |
| | | } |
| | | |
| | | /** |
| | | * JSAPI下单 |
| | | * @param sessionId |
| | | * @param orderNumber |
| | | * @param payAmount |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | @Operation(summary = "统一下单", description = "统一下单") |
| | | @ApiResponses(value = { |
| | | @ApiResponse( |
| | | responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE, |
| | | description = "操作结果:true:成功,false:失败(BaseResponse.content)", |
| | | content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, |
| | | schema = @Schema(implementation = Boolean.class))} |
| | | ) |
| | | }) |
| | | @PostMapping(path = "unifiedOrder") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @SsoAop() |
| | | public BaseResponse<Boolean> unifiedOrder(@RequestParam("sessionId") String sessionId, @RequestParam("orderNumber") String orderNumber, @RequestParam("payAmount") String payAmount) throws Exception { |
| | | String prepayId = ""; |
| | | SeWebchatLogonState po = paymentSv.selectOne(Long.parseLong(sessionId)); |
| | | String openid = po.getOpenId(); |
| | | |
| | | JSONObject job_body = new JSONObject(); |
| | | job_body.put("appid", PayInfo.appid); |
| | | job_body.put("mchid", PayInfo.mchid); |
| | | job_body.put("description", PayInfo.description); |
| | | job_body.put("out_trade_no", orderNumber); |
| | | job_body.put("notify_url", PayInfo.notifyUrl); |
| | | |
| | | //订单金额 |
| | | JSONObject job_amount = new JSONObject(); |
| | | job_amount.put("total", 1); |
| | | job_amount.put("currency", "CNY"); |
| | | job_body.put("amount", job_amount); |
| | | |
| | | //支付者 |
| | | JSONObject job_payer = new JSONObject(); |
| | | job_payer.put("openid", openid); |
| | | job_body.put("payer", job_payer); |
| | | |
| | | // 获取随机串和时间戳,放在此处以保证 |
| | | String nonceStr = PayHelper.generateRandomString(); |
| | | Long timestamp = System.currentTimeMillis() / 1000; |
| | | |
| | | String method = "POST"; |
| | | String httpUrl = "/v3/pay/transactions/jsapi"; |
| | | |
| | | String body = job_body.toJSONString(); |
| | | String header = PayInfo.schema + " " + PayHelper.getToken(method, httpUrl, body, nonceStr, timestamp, certFileName); |
| | | |
| | | Map<String, String> headers = new HashMap<>(); |
| | | headers.put("Authorization", header); |
| | | headers.put("Accept", "application/json"); |
| | | headers.put("Content-Type", "application/json"); |
| | | |
| | | JSONObject job_result = restTemplateUtil.post(PayInfo.orderUrl, body, headers); |
| | | if(job_result != null) { |
| | | System.out.println(job_result.toString()); |
| | | prepayId = job_result.getString("prepay_id"); |
| | | } |
| | | |
| | | |
| | | |
| | | //String result = OkHttpUtil.builder().url(PayInfo.orderUrl) |
| | | // .addBody(body) |
| | | // .addHeader("Authorization", header) |
| | | // .addHeader("Accept", "application/json") |
| | | // .addHeader("Content-Type", "application/json") |
| | | // .initPost(true) |
| | | // .sync(); |
| | | //System.out.println(result); |
| | | |
| | | return BaseResponseUtils.buildSuccess(prepayId) ; |
| | | } |
| | | |
| | | /** |
| | | * 再次签名 |
| | | * @param prepayId 预支付交易会话标识 |
| | | * @return 小程序调起支付参数 |
| | | * @throws Exception |
| | | */ |
| | | @Operation(summary = "再次签名", description = "再次签名") |
| | | @ApiResponses(value = { |
| | | @ApiResponse( |
| | | responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE, |
| | | description = "操作结果:true:成功,false:失败(BaseResponse.content)", |
| | | content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, |
| | | schema = @Schema(implementation = Boolean.class))} |
| | | ) |
| | | }) |
| | | @GetMapping(path = "/signAgain") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @SsoAop() |
| | | public BaseResponse<JSONObject> signAgain(@RequestParam("prepayId") String prepayId) throws Exception { |
| | | |
| | | // 获取随机串和时间戳,放在此处以保证 |
| | | String appid = PayInfo.appid; |
| | | String timestamp = String.valueOf(System.currentTimeMillis() / 1000); |
| | | String nonceStr = PayHelper.generateRandomString(); |
| | | String pkg = "prepay_id=" + prepayId; |
| | | String signType = PayInfo.signType; |
| | | String message = PayHelper.buildMessage_signAgain(appid, timestamp, nonceStr, pkg); |
| | | String paySign = PayHelper.sign(message.getBytes("utf-8"), certFileName); |
| | | |
| | | JSONObject job_result = new JSONObject(); |
| | | job_result.put("timestamp", timestamp); |
| | | job_result.put("nonceStr", nonceStr); |
| | | job_result.put("package", pkg); |
| | | job_result.put("signType", signType); |
| | | job_result.put("paySign", paySign); |
| | | |
| | | return BaseResponseUtils.buildSuccess(job_result) ; |
| | | } |
| | | } |
New file |
| | |
| | | package com.dy.pipirrWebChat.payment; |
| | | |
| | | import com.dy.pipIrrGlobal.daoSe.SeWebchatLogonStateMapper; |
| | | import com.dy.pipIrrGlobal.pojoSe.SeWebchatLogonState; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | /** |
| | | * @author ZhuBaoMin |
| | | * @date 2024-02-22 17:39 |
| | | * @LastEditTime 2024-02-22 17:39 |
| | | * @Description |
| | | */ |
| | | |
| | | @Slf4j |
| | | @Service |
| | | public class PaymentSv { |
| | | @Autowired |
| | | private SeWebchatLogonStateMapper seWebchatLogonStateMapper; |
| | | |
| | | /** |
| | | * 添加登录态状态记录 |
| | | * @param po |
| | | * @return |
| | | */ |
| | | Long insert(SeWebchatLogonState po) { |
| | | seWebchatLogonStateMapper.insert(po); |
| | | return po.getId(); |
| | | } |
| | | |
| | | SeWebchatLogonState selectOne(Long id) { |
| | | return seWebchatLogonStateMapper.selectByPrimaryKey(id); |
| | | } |
| | | } |
New file |
| | |
| | | package com.dy.pipirrWebChat.payment.dto; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author ZhuBaoMin |
| | | * @date 2024-02-22 15:34 |
| | | * @LastEditTime 2024-02-22 15:34 |
| | | * @Description |
| | | */ |
| | | |
| | | @Data |
| | | @Schema(name = "登录凭证校验传入对象") |
| | | public class Code2Session { |
| | | public static final long serialVersionUID = 202402221335001L; |
| | | |
| | | /** |
| | | * 小程序 appId |
| | | */ |
| | | @Schema(description = "小程序 appId", requiredMode = Schema.RequiredMode.NOT_REQUIRED) |
| | | @NotBlank(message = "小程序 appId不能为空") |
| | | private String appid; |
| | | |
| | | /** |
| | | * 小程序 appSecret |
| | | */ |
| | | @Schema(description = "小程序 appSecret", requiredMode = Schema.RequiredMode.NOT_REQUIRED) |
| | | @NotBlank(message = "小程序 appSecret不能为空") |
| | | private String secret; |
| | | |
| | | /** |
| | | * js_code |
| | | */ |
| | | @Schema(description = "js_code", requiredMode = Schema.RequiredMode.NOT_REQUIRED) |
| | | @NotBlank(message = "js_code不能为空") |
| | | private String js_code; |
| | | } |
New file |
| | |
| | | package com.dy.pipirrWebChat.util; |
| | | |
| | | import okhttp3.Call; |
| | | |
| | | /** |
| | | * @author ZhuBaoMin |
| | | * @date 2024-02-22 15:22 |
| | | * @LastEditTime 2024-02-22 15:22 |
| | | * @Description |
| | | */ |
| | | |
| | | public interface ICallback { |
| | | void onSuccess(Call call, String data); |
| | | void onFail(Call call, String errorMsg); |
| | | } |
New file |
| | |
| | | package com.dy.pipirrWebChat.util; |
| | | |
| | | import okhttp3.*; |
| | | import org.jetbrains.annotations.NotNull; |
| | | |
| | | import javax.net.ssl.SSLContext; |
| | | import javax.net.ssl.SSLSocketFactory; |
| | | import javax.net.ssl.TrustManager; |
| | | import javax.net.ssl.X509TrustManager; |
| | | import java.io.IOException; |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.net.URLEncoder; |
| | | import java.security.SecureRandom; |
| | | import java.security.cert.CertificateException; |
| | | import java.security.cert.X509Certificate; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.concurrent.Semaphore; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | /** |
| | | * @author ZhuBaoMin |
| | | * @date 2024-02-22 13:39 |
| | | * @LastEditTime 2024-02-22 13:39 |
| | | * @Description |
| | | */ |
| | | |
| | | public class OkHttpUtil { |
| | | |
| | | private static volatile OkHttpClient okHttpClient = null; |
| | | private static volatile Semaphore semaphore = null; |
| | | private Map<String, String> headerMap; |
| | | private Map<String, Object> paramMap; |
| | | private String url; |
| | | private Request.Builder request; |
| | | private String body; |
| | | |
| | | private OkHttpUtil() { |
| | | if (Objects.isNull(okHttpClient)) { |
| | | synchronized (OkHttpUtil.class) { |
| | | if (Objects.isNull(okHttpClient)) { |
| | | TrustManager[] trustManagers = buildTrustManager(); |
| | | okHttpClient = new OkHttpClient.Builder() |
| | | .connectTimeout(15, TimeUnit.SECONDS) |
| | | .writeTimeout(20, TimeUnit.SECONDS) |
| | | .readTimeout(20, TimeUnit.SECONDS) |
| | | .sslSocketFactory(createSSLSocketFactory(trustManagers), (X509TrustManager)trustManagers[0]) |
| | | .hostnameVerifier((hostname, session) -> true) |
| | | .retryOnConnectionFailure(true) |
| | | .build(); |
| | | addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | public OkHttpUtil initGet() { |
| | | request = new Request.Builder().get(); |
| | | StringBuilder builder = new StringBuilder(url); |
| | | if (Objects.nonNull(paramMap)) { |
| | | builder.append("?"); |
| | | paramMap.forEach((key, value) -> { |
| | | try { |
| | | builder.append(URLEncoder.encode(key, "utf-8")) |
| | | .append("=") |
| | | .append(URLEncoder.encode((String)value, "utf-8")) |
| | | .append("&"); |
| | | } catch (UnsupportedEncodingException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | }); |
| | | builder.deleteCharAt(builder.length() - 1); |
| | | } |
| | | request.url(builder.toString()); |
| | | return this; |
| | | } |
| | | |
| | | public OkHttpUtil initPost(boolean isJson) { |
| | | RequestBody requestBody = null; |
| | | if (isJson) { |
| | | requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), body); |
| | | } else { |
| | | FormBody.Builder formBody = new FormBody.Builder(); |
| | | if (Objects.nonNull(paramMap)) { |
| | | paramMap.forEach((x, y) -> formBody.add(x, (String) y)); |
| | | } |
| | | requestBody = formBody.build(); |
| | | } |
| | | request = new Request.Builder().post(requestBody).url(url); |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * @Description:同步请求 |
| | | * @Author: zzc |
| | | * @Date: 2022-12-04 18:06 |
| | | * @return: java.lang.String |
| | | **/ |
| | | public String sync() throws Exception { |
| | | setHeader(request); |
| | | try { |
| | | Response result = okHttpClient.newCall(request.build()).execute(); |
| | | if (result.isSuccessful()) { |
| | | return result.body().string(); |
| | | } |
| | | throw new Exception(result.body().string()); |
| | | } catch (IOException e) { |
| | | throw new Exception(e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * @Description:异步请求,有返回值 |
| | | * @Author: zzc |
| | | * @Date: 2022-12-04 18:05 |
| | | * @return: java.lang.String |
| | | **/ |
| | | public String async() { |
| | | StringBuffer buffer = new StringBuffer(); |
| | | setHeader(request); |
| | | okHttpClient.newCall(request.build()).enqueue(new Callback() { |
| | | @Override |
| | | public void onResponse(@NotNull okhttp3.Call call, @NotNull Response response) throws IOException { |
| | | if (Objects.nonNull(response.body())) { |
| | | buffer.append(response.body().string()); |
| | | getSemaphore().release(); |
| | | } |
| | | } |
| | | @Override |
| | | public void onFailure(@NotNull okhttp3.Call call, @NotNull IOException e) { |
| | | buffer.append("请求出错").append(e.getMessage()); |
| | | } |
| | | }); |
| | | try { |
| | | getSemaphore().acquire(); |
| | | } catch (InterruptedException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | private static Semaphore getSemaphore() { |
| | | synchronized (OkHttpUtil.class) { |
| | | if (Objects.isNull(semaphore)) { |
| | | semaphore = new Semaphore(0); |
| | | } |
| | | } |
| | | return semaphore; |
| | | } |
| | | |
| | | public static OkHttpUtil builder() { |
| | | return new OkHttpUtil(); |
| | | } |
| | | |
| | | public OkHttpUtil url(String url) { |
| | | this.url = url; |
| | | return this; |
| | | } |
| | | |
| | | public OkHttpUtil addParam(String key, String value) { |
| | | if (Objects.isNull(paramMap)) { |
| | | paramMap = new LinkedHashMap<>(16); |
| | | } |
| | | paramMap.put(key, value); |
| | | return this; |
| | | } |
| | | |
| | | public OkHttpUtil addBody(String body) { |
| | | this.body = body; |
| | | return this; |
| | | } |
| | | |
| | | public void setHeader(Request.Builder request) { |
| | | if (Objects.nonNull(headerMap)) { |
| | | headerMap.forEach(request::addHeader); |
| | | } |
| | | } |
| | | |
| | | public OkHttpUtil addHeader(String key, String value) { |
| | | if (Objects.isNull(headerMap)) { |
| | | headerMap = new LinkedHashMap<>(16); |
| | | } |
| | | headerMap.put(key, value); |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * @Description:生成安全套接字工厂,用于Https请求的证书跳过 |
| | | * @Author: zzc |
| | | * @Date: 2022-11-30 16:03 |
| | | * @param trustManagers: |
| | | * @return: javax.net.ssl.SSLSocketFactory |
| | | **/ |
| | | //private static SSLSocketFactory createSSLSocketFactory(TrustManager[] trustManagers) { |
| | | // SSLSocketFactory sslSocketFactory = null; |
| | | // try { |
| | | // SSLContext ssl = SSLContext.getInstance("SSL"); |
| | | // ssl.init(null, trustManagers, new SecureRandom()); |
| | | // sslSocketFactory = ssl.getSocketFactory(); |
| | | // } catch (Exception e) { |
| | | // e.printStackTrace(); |
| | | // } |
| | | // return sslSocketFactory; |
| | | //} |
| | | |
| | | private static SSLSocketFactory createSSLSocketFactory(TrustManager[] trustManagers) { |
| | | SSLSocketFactory sslSocketFactory = null; |
| | | try { |
| | | SSLContext ssl = SSLContext.getInstance("SSL"); |
| | | ssl.init(null, trustManagers, new SecureRandom()); |
| | | sslSocketFactory = ssl.getSocketFactory(); |
| | | |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return sslSocketFactory; |
| | | } |
| | | |
| | | private static TrustManager[] buildTrustManager() { |
| | | return new TrustManager[] { |
| | | new X509TrustManager() { |
| | | @Override |
| | | public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { |
| | | } |
| | | |
| | | @Override |
| | | public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { |
| | | } |
| | | |
| | | @Override |
| | | public X509Certificate[] getAcceptedIssuers() { |
| | | return new X509Certificate[]{}; |
| | | } |
| | | } |
| | | }; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.dy.pipirrWebChat.util; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.http.*; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.MultiValueMap; |
| | | import org.springframework.web.client.RestTemplate; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * @author ZhuBaoMin |
| | | * @date 2024-02-23 15:42 |
| | | * @LastEditTime 2024-02-23 15:42 |
| | | * @Description |
| | | */ |
| | | |
| | | @Component |
| | | public class RestTemplateUtil { |
| | | |
| | | @Autowired |
| | | private RestTemplate restTemplate; |
| | | |
| | | //@Qualifier("RestTemplateWithCert") |
| | | //@Resource |
| | | //private RestTemplate restTemplate; |
| | | |
| | | public JSONObject get(String url, Map<String, Object> queryParams) throws IOException { |
| | | return get(url, queryParams, new HashMap<>(1)); |
| | | } |
| | | |
| | | public JSONObject get(String url, Map<String, Object> queryParams, Map<String, String> headerParams) throws IOException { |
| | | String tempUrl = setParamsByAppendUrl(queryParams, url); |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headerParams.forEach(headers::add); |
| | | HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(null, headers); |
| | | ResponseEntity<String> response = restTemplate.exchange(tempUrl, HttpMethod.GET, httpEntity, String.class); |
| | | return JSONObject.parseObject(response.getBody()); |
| | | } |
| | | |
| | | public JSONObject get2(String url, Map<String, Object> queryParams, Map<String, String> headerParams) throws IOException { |
| | | String tempUrl = setParamsByPath(queryParams, url); |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headerParams.forEach(headers::add); |
| | | HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(null, headers); |
| | | ResponseEntity<String> response = restTemplate.exchange(tempUrl, HttpMethod.GET, httpEntity, String.class, queryParams); |
| | | return JSONObject.parseObject(response.getBody()); |
| | | } |
| | | |
| | | public JSONObject post(String url, String json, Map<String, String> headerParams) { |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headerParams.forEach(headers::add); |
| | | headers.setContentType(MediaType.APPLICATION_JSON); |
| | | headers.add("Accept", MediaType.APPLICATION_JSON.toString()); |
| | | HttpEntity<String> httpEntity = new HttpEntity<>(json, headers); |
| | | ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); |
| | | return JSONObject.parseObject(response.getBody()); |
| | | } |
| | | |
| | | private String setParamsByPath(Map<String, Object> queryParams, String url) { |
| | | // url?id={id}&name={name} |
| | | if (queryParams == null || queryParams.isEmpty()) { |
| | | return url; |
| | | } |
| | | StringBuilder sb = new StringBuilder(); |
| | | try { |
| | | for (Map.Entry<String, Object> entry : queryParams.entrySet()) { |
| | | sb.append("&").append(entry.getKey()).append("=").append("{").append(entry.getKey()).append("}"); |
| | | } |
| | | if (!url.contains("?")) { |
| | | sb.deleteCharAt(0).insert(0, "?"); |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return url + sb; |
| | | } |
| | | |
| | | private String setParamsByAppendUrl(Map<String, Object> queryParams, String url) { |
| | | // url?id=1&name=zzc |
| | | if (queryParams == null || queryParams.isEmpty()) { |
| | | return url; |
| | | } |
| | | StringBuilder sb = new StringBuilder(); |
| | | try { |
| | | for (Map.Entry<String, Object> entry : queryParams.entrySet()) { |
| | | sb.append("&").append(entry.getKey()).append("="); |
| | | sb.append(entry.getValue()); |
| | | } |
| | | if (!url.contains("?")) { |
| | | sb.deleteCharAt(0).insert(0, "?"); |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return url + sb; |
| | | } |
| | | |
| | | } |
| | |
| | | #actutor的web端口 |
| | | management: |
| | | server: |
| | | port: ${pipIrr.project.actutorPort} |
| | | port: ${pipIrr.webchat.actutorPort} |
| | | #web服务端口,8086 |
| | | server: |
| | | port: ${pipIrr.webchat.webPort} |
| | | servlet: |
| | | context-path: /webchat #web访问上下文路径 |
| | | context-path: /webchat #webchat访问上下文路径 |
| | | context-parameters: |
| | | #GenerateIdSetSuffixListener中应用,取值范围是0-99 |
| | | idSuffix: ${pipIrr.webchat.idSuffix} |