zhaoyiran
7 months ago
19 changed files with 955 additions and 118 deletions
@ -1,100 +1,118 @@ |
|||||
<?xml version="1.0" encoding="UTF-8"?> |
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
<modelVersion>4.0.0</modelVersion> |
||||
<parent> |
<parent> |
||||
<groupId>org.springframework.boot</groupId> |
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-parent</artifactId> |
<artifactId>spring-boot-starter-parent</artifactId> |
||||
<version>2.7.15</version> |
<version>2.7.15</version> |
||||
<relativePath/> <!-- lookup parent from repository --> |
<relativePath/> <!-- lookup parent from repository --> |
||||
</parent> |
</parent> |
||||
<groupId>com.win</groupId> |
<groupId>com.win</groupId> |
||||
<artifactId>qad</artifactId> |
<artifactId>bank</artifactId> |
||||
<version>1.0.0</version> |
<version>1.0.0</version> |
||||
<name>mq</name> |
<name>bank</name> |
||||
<description>win mq</description> |
<description>win bank</description> |
||||
<properties> |
<properties> |
||||
<java.version>17</java.version> |
<java.version>17</java.version> |
||||
</properties> |
</properties> |
||||
<dependencies> |
<dependencies> |
||||
|
<dependency> |
||||
|
<groupId>org.bouncycastle</groupId> |
||||
|
<artifactId>bcprov-jdk15on</artifactId> |
||||
|
<version>1.61</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>com.google.code.gson</groupId> |
||||
|
<artifactId>gson</artifactId> |
||||
|
<version>2.8.6</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>dom4j</groupId> |
||||
|
<artifactId>dom4j</artifactId> |
||||
|
<version>1.1</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>com.jcraft</groupId> |
||||
|
<artifactId>jsch</artifactId> |
||||
|
<version>0.1.55</version> |
||||
|
</dependency> |
||||
|
|
||||
<dependency> |
<dependency> |
||||
<groupId>com.jcraft</groupId> |
<groupId>org.apache.commons</groupId> |
||||
<artifactId>jsch</artifactId> |
<artifactId>commons-lang3</artifactId> |
||||
<version>0.1.55</version> |
<version>3.14.0</version> |
||||
</dependency> |
</dependency> |
||||
|
|
||||
<dependency> |
<dependency> |
||||
<groupId>org.apache.commons</groupId> |
<groupId>mysql</groupId> |
||||
<artifactId>commons-lang3</artifactId> |
<artifactId>mysql-connector-java</artifactId> |
||||
<version>3.9</version> |
<version>8.0.33</version> |
||||
</dependency> |
</dependency> |
||||
|
|
||||
<dependency> |
<dependency> |
||||
<groupId>org.apache.commons</groupId> |
<groupId>com.alibaba</groupId> |
||||
<artifactId>commons-exec</artifactId> |
<artifactId>fastjson</artifactId> |
||||
<version>1.3</version> |
<version>1.2.83</version> |
||||
</dependency> |
</dependency> |
||||
|
|
||||
<dependency> |
<dependency> |
||||
<groupId>com.alibaba</groupId> |
<groupId>org.projectlombok</groupId> |
||||
<artifactId>fastjson</artifactId> |
<artifactId>lombok</artifactId> |
||||
<version>1.2.83</version> |
<version>1.18.28</version> |
||||
</dependency> |
</dependency> |
||||
|
|
||||
<dependency> |
<dependency> |
||||
<groupId>org.projectlombok</groupId> |
<groupId>com.alibaba</groupId> |
||||
<artifactId>lombok</artifactId> |
<artifactId>druid-spring-boot-starter</artifactId> |
||||
<version>1.18.28</version> |
<version>1.2.19</version> |
||||
</dependency> |
</dependency> |
||||
|
|
||||
<dependency> |
<dependency> |
||||
<groupId>com.alibaba</groupId> |
<groupId>com.baomidou</groupId> |
||||
<artifactId>druid-spring-boot-starter</artifactId> |
<artifactId>mybatis-plus-boot-starter</artifactId> |
||||
<version>1.2.19</version> |
<version>3.5.3.2</version> |
||||
</dependency> |
</dependency> |
||||
|
|
||||
<dependency> |
<dependency> |
||||
<groupId>com.baomidou</groupId> |
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>mybatis-plus-boot-starter</artifactId> |
<artifactId>spring-boot-starter</artifactId> |
||||
<version>3.5.3.2</version> |
</dependency> |
||||
</dependency> |
|
||||
|
|
||||
<dependency> |
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter</artifactId> |
<artifactId>spring-boot-starter-test</artifactId> |
||||
</dependency> |
<scope>test</scope> |
||||
|
</dependency> |
||||
|
|
||||
<dependency> |
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-test</artifactId> |
<artifactId>spring-boot-starter-web</artifactId> |
||||
<scope>test</scope> |
</dependency> |
||||
</dependency> |
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-jdbc</artifactId> |
||||
|
</dependency> |
||||
|
</dependencies> |
||||
|
|
||||
<dependency> |
|
||||
<groupId>org.springframework.boot</groupId> |
|
||||
<artifactId>spring-boot-starter-web</artifactId> |
|
||||
</dependency> |
|
||||
|
|
||||
</dependencies> |
<build> |
||||
|
<!-- 设置构建的 jar 包名 --> |
||||
<build> |
<finalName>${project.artifactId}</finalName> |
||||
<!-- 设置构建的 jar 包名 --> |
<plugins> |
||||
<finalName>${project.artifactId}</finalName> |
<!-- 打包 --> |
||||
<plugins> |
<plugin> |
||||
<!-- 打包 --> |
<groupId>org.springframework.boot</groupId> |
||||
<plugin> |
<artifactId>spring-boot-maven-plugin</artifactId> |
||||
<groupId>org.springframework.boot</groupId> |
<executions> |
||||
<artifactId>spring-boot-maven-plugin</artifactId> |
<execution> |
||||
<executions> |
<goals> |
||||
<execution> |
<goal>repackage</goal> <!-- 将引入的 jar 打入其中 --> |
||||
<goals> |
</goals> |
||||
<goal>repackage</goal> <!-- 将引入的 jar 打入其中 --> |
</execution> |
||||
</goals> |
</executions> |
||||
</execution> |
</plugin> |
||||
</executions> |
</plugins> |
||||
</plugin> |
</build> |
||||
</plugins> |
|
||||
</build> |
|
||||
|
|
||||
</project> |
</project> |
||||
|
@ -1,18 +1,27 @@ |
|||||
package com.win.bank; |
package com.win.bank; |
||||
|
|
||||
|
import org.mybatis.spring.annotation.MapperScan; |
||||
import org.springframework.boot.SpringApplication; |
import org.springframework.boot.SpringApplication; |
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
import org.springframework.context.annotation.ComponentScan; |
||||
|
import org.springframework.scheduling.annotation.EnableScheduling; |
||||
|
|
||||
/** |
/** |
||||
* 启动程序 |
* 启动程序 |
||||
* |
* |
||||
* @author win |
* @author win |
||||
*/ |
*/ |
||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) |
// @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
|
||||
|
@SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${win.info.base-package}
|
||||
|
// @SpringBootApplication(scanBasePackages = {"${win.info.base-package}.server", "${win.info.base-package}.module"},
|
||||
|
// exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class})
|
||||
|
@SpringBootApplication(scanBasePackages = {"${win.info.base-package}.server", "${win.info.base-package}.module"}) |
||||
|
@EnableScheduling |
||||
|
@ComponentScan("com.win") |
||||
|
@MapperScan("com.win.bank.dal.mysql") |
||||
public class Application { |
public class Application { |
||||
public static void main(String[] args) { |
public static void main(String[] args) { |
||||
SpringApplication.run(Application.class, args); |
SpringApplication.run(Application.class, args); |
||||
System.out.println("闻音启动成功"); |
System.out.println("闻音启动成功"); |
||||
} |
} |
||||
} |
} |
||||
|
@ -0,0 +1,28 @@ |
|||||
|
package com.win.bank.config; |
||||
|
|
||||
|
import javax.sql.DataSource; |
||||
|
|
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.session.SqlSessionFactory; |
||||
|
import org.mybatis.spring.SqlSessionFactoryBean; |
||||
|
import org.mybatis.spring.SqlSessionTemplate; |
||||
|
import org.mybatis.spring.annotation.MapperScan; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
|
||||
|
@Configuration |
||||
|
@MapperScan(value = "com.win.bank", annotationClass = Mapper.class) // Mapper 懒加载,目前仅用于单元测试
|
||||
|
public class MyBatisConfig { |
||||
|
|
||||
|
@Bean |
||||
|
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { |
||||
|
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); |
||||
|
sqlSessionFactoryBean.setDataSource(dataSource); |
||||
|
return sqlSessionFactoryBean.getObject(); |
||||
|
} |
||||
|
|
||||
|
@Bean |
||||
|
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { |
||||
|
return new SqlSessionTemplate(sqlSessionFactory); |
||||
|
} |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
package com.win.bank.dal.dataobject; |
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
|
||||
|
public abstract class BaseDO implements Serializable {} |
@ -0,0 +1,77 @@ |
|||||
|
package com.win.bank.dal.dataobject.bank; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.annotation.TableId; |
||||
|
import com.baomidou.mybatisplus.annotation.TableName; |
||||
|
import com.win.bank.dal.dataobject.BaseDO; |
||||
|
|
||||
|
import lombok.*; |
||||
|
|
||||
|
/** |
||||
|
* 银企直联 DO |
||||
|
* |
||||
|
* @author 超级管理员 |
||||
|
*/ |
||||
|
@TableName("basic_bank") |
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@ToString(callSuper = true) |
||||
|
@Builder |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class BankDO extends BaseDO { |
||||
|
/** |
||||
|
* id |
||||
|
*/ |
||||
|
@TableId |
||||
|
private Long id; |
||||
|
/** |
||||
|
* 状态,0:未处理;1:支付中;2:支付成功;3:支付失败 |
||||
|
*/ |
||||
|
private String status; |
||||
|
/** |
||||
|
* 付款银行编码,例:CMB:招商银行;ICBC:工商银行;BC:中国银行 |
||||
|
*/ |
||||
|
private String payBankCode; |
||||
|
/** |
||||
|
* 付款账号 |
||||
|
*/ |
||||
|
private String payAccount; |
||||
|
/** |
||||
|
* 收款账号 |
||||
|
*/ |
||||
|
private String rcvAccount; |
||||
|
/** |
||||
|
* 收款户名 |
||||
|
*/ |
||||
|
private String rcvUserName; |
||||
|
/** |
||||
|
* 收款方开户行名称 |
||||
|
*/ |
||||
|
private String rcvBankName; |
||||
|
/** |
||||
|
* 收款方开户行地址 |
||||
|
*/ |
||||
|
private String rcvBankAddress; |
||||
|
/** |
||||
|
* 收款方联行号 |
||||
|
*/ |
||||
|
private String rcvBankNumber; |
||||
|
/** |
||||
|
* 交易金额 |
||||
|
*/ |
||||
|
private BigDecimal amount; |
||||
|
/** |
||||
|
* 用途 |
||||
|
*/ |
||||
|
private String purpose; |
||||
|
/** |
||||
|
* 提示信息 |
||||
|
*/ |
||||
|
private String message; |
||||
|
/** |
||||
|
* 流水号 |
||||
|
*/ |
||||
|
private String serialNumber; |
||||
|
} |
@ -0,0 +1,9 @@ |
|||||
|
package com.win.bank.dal.mysql.bank; |
||||
|
|
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
|
import com.win.bank.dal.dataobject.bank.BankDO; |
||||
|
|
||||
|
@Mapper |
||||
|
public interface BankMapper extends BaseMapper<BankDO> {} |
@ -0,0 +1,29 @@ |
|||||
|
package com.win.bank.service; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
import javax.annotation.Resource; |
||||
|
|
||||
|
import org.springframework.scheduling.annotation.Scheduled; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import com.win.bank.dal.dataobject.bank.BankDO; |
||||
|
import com.win.bank.service.bank.BankService; |
||||
|
|
||||
|
@Component |
||||
|
public class MainService { |
||||
|
|
||||
|
@Resource |
||||
|
private BankService bankService; |
||||
|
|
||||
|
@Scheduled(cron = "* * * * * ?") |
||||
|
public void task() { |
||||
|
System.out.println(System.currentTimeMillis()); |
||||
|
|
||||
|
List<BankDO> bankDOList = bankService.listByStatus("0"); |
||||
|
|
||||
|
for (BankDO bankDO : bankDOList) { |
||||
|
System.out.println(bankDO); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
package com.win.bank.service.bank; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.extension.service.IService; |
||||
|
import com.win.bank.dal.dataobject.bank.BankDO; |
||||
|
|
||||
|
public interface BankService extends IService<BankDO> { |
||||
|
List<BankDO> listByStatus(String status); |
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
package com.win.bank.service.bank; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
||||
|
import com.win.bank.dal.dataobject.bank.BankDO; |
||||
|
import com.win.bank.dal.mysql.bank.BankMapper; |
||||
|
|
||||
|
@Service |
||||
|
public class BankServiceImpl extends ServiceImpl<BankMapper, BankDO> implements BankService { |
||||
|
|
||||
|
@Override |
||||
|
public List<BankDO> listByStatus(String status) { |
||||
|
QueryWrapper<BankDO> queryWrapper = new QueryWrapper<>(); |
||||
|
queryWrapper.eq("status", status); |
||||
|
return list(queryWrapper); |
||||
|
} |
||||
|
} |
@ -0,0 +1,73 @@ |
|||||
|
package com.win.bank.service.cmb; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.security.GeneralSecurityException; |
||||
|
import java.security.Security; |
||||
|
import java.text.SimpleDateFormat; |
||||
|
import java.util.Date; |
||||
|
import java.util.Random; |
||||
|
|
||||
|
import org.bouncycastle.crypto.CryptoException; |
||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider; |
||||
|
|
||||
|
/** |
||||
|
* 招商银行银企直联国密免前置/SaaS对接示例,本示例仅供参考,不保证各种异常场景运行,请勿直接使用,如有错漏请联系对接人员。运行时,请使用所获取的测试资源替换 用户编号、公私钥、对称密钥、服务商编号等信息。 |
||||
|
* |
||||
|
* @author cmb.firmbank |
||||
|
* @date 2023/7/20 |
||||
|
*/ |
||||
|
public class ApiDemo { |
||||
|
|
||||
|
private static final int BOUND_START = 1000000; |
||||
|
private static final int BOUND_END = 9000000; |
||||
|
// 测试地址,生产需要替换
|
||||
|
private static String url = "http://192.168.0.142:8080/cdcserver/api/v2"; |
||||
|
// private static String url = "http://cdctest.cmburl.cn:80/cdcserver/api/v2";
|
||||
|
// 生产地址
|
||||
|
// private static String url = "https://cdc.cmbchina.com/cdcserver/api/v2";
|
||||
|
// 银行公钥,生产需要替换
|
||||
|
private static String publicKey = "BNsIe9U0x8IeSe4h/dxUzVEz9pie0hDSfMRINRXc7s1UIXfkExnYECF4QqJ2SnHxLv3z/99gsfDQrQ6dzN5lZj0="; |
||||
|
// 生产环境银行公钥
|
||||
|
// private static String publicKey =
|
||||
|
// "BEynMEZOjNpwZIiD9jXtZSGr3Ecpwn7r+m+wtafXHb6VIZTnugfuxhcKASq3hX+KX9JlHODDl9/RDKQv4XLOFak=";
|
||||
|
// 客户私钥,生产需要替换
|
||||
|
private static String privateKey = "NBtl7WnuUtA2v5FaebEkU0/Jj1IodLGT6lQqwkzmd2E="; |
||||
|
// 对称密钥,生产需要替换
|
||||
|
private static String symKey = "VuAzSWQhsoNqzn0K"; |
||||
|
|
||||
|
// 企业网银用户号,生产需要替换
|
||||
|
private static String uid = "N002986522"; |
||||
|
|
||||
|
private static Random random = new Random(); |
||||
|
|
||||
|
private ApiDemo() {} |
||||
|
|
||||
|
public static void main(String[] args) throws GeneralSecurityException, IOException, CryptoException { |
||||
|
// 装载BC库,必须在应用的启动类中调用此函数
|
||||
|
Security.addProvider(new BouncyCastleProvider()); |
||||
|
System.setProperty("sun.net.http.retryPost", "false"); |
||||
|
|
||||
|
// 业务接口名,这里是查询业务模式接口,生产请替换为对应接口名
|
||||
|
String funcode = "BB1PAYQR"; |
||||
|
// 准备接口数据,生产请替换为具体接口请求报文,包含所需的请求字段
|
||||
|
String currentDatetime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); |
||||
|
String reqid = new SimpleDateFormat("yyyyMMddHHmmssSSSS").format(new Date()) + (BOUND_START + random.nextInt(BOUND_END)); |
||||
|
String data = |
||||
|
"{\"request\":{\"body\":{\"bb1paybmx1\":[{\"busCod\":\"N02030\",\"busMod\":\"00002\"}],\"bb1payopx1\":[{\"ccyNbr\":\"10\",\"crtAcc\":\"6214831150131511\",\"crtNam\":\"吴极客\",\"dbtAcc\":\"755936045010501\",\"nusAge\":\"用途\",\"bnkFlg\":\"Y\",\"trsAmt\":\"1.05\",\"yurRef\":\"2024041709400601\"}]},\"head\":{\"funcode\":\"BB1PAYOP\",\"userid\":\"N002986522\"}}}"; |
||||
|
|
||||
|
// String data =
|
||||
|
// "{\"request\":{\"body\":{\"bb1payqrx1\":[{\"busCod\":\"N02030\",\"yurRef\":\"2024041709400602\"}]},\"head\":{\"funcode\":\"BB1PAYQR\",\"userid\":\"N002986522\"}}}";
|
||||
|
System.out.println(data); |
||||
|
DcHelper dchelper = new DcHelper(url, uid, privateKey, publicKey, symKey); |
||||
|
// 添加设备信息,请根据文档指引填写真实的信息,参数按顺序分别为:出口IP(无需)、MAC地址、CPU-ID、计算机名、主板ID、主板厂商
|
||||
|
// DeviceInfo deviceInfo = new DeviceInfo(null, "9822EFF12C6B", "AABBCCDDEEFFGGHH", "XXX", "XXX", "XXX");
|
||||
|
// String response = dchelper.sendRequest(data, funcode);
|
||||
|
// process("Api请求1成功,响应报文:\r\n" + response);
|
||||
|
// String response2 = dchelper.sendRequest(data, funcode, deviceInfo);
|
||||
|
// process("Api请求2成功,响应报文:\r\n" + response2);
|
||||
|
} |
||||
|
|
||||
|
private static void process(String response) { |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
package com.win.bank.service.cmb; |
||||
|
|
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import com.google.gson.Gson; |
||||
|
import com.google.gson.JsonArray; |
||||
|
import com.google.gson.JsonObject; |
||||
|
import com.win.bank.dal.dataobject.bank.BankDO; |
||||
|
|
||||
|
@Service |
||||
|
public class CmbServiceImpl { |
||||
|
|
||||
|
public String payment(BankDO bankDO) { |
||||
|
String data = "{\"request\":{\"body\":{\"bb1paybmx1\":[{\"busCod\":\"N02030\",\"busMod\":\"00002\"}]},\"head\":{\"funcode\":\"BB1PAYOP\",\"userid\":\"N002986522\"}}}"; |
||||
|
JsonObject requestJson = new Gson().fromJson(data, JsonObject.class); |
||||
|
JsonArray bb1payopx1 = new JsonArray(); |
||||
|
JsonObject info = new JsonObject(); |
||||
|
info.addProperty("dbtAcc", bankDO.getPayAccount()); |
||||
|
info.addProperty("crtAcc", bankDO.getRcvAccount()); |
||||
|
info.addProperty("crtNam", bankDO.getRcvUserName()); |
||||
|
info.addProperty("ccyNbr", "10"); |
||||
|
info.addProperty("trsAmt", bankDO.getAmount().toString()); |
||||
|
info.addProperty("nusAge", bankDO.getPurpose()); |
||||
|
info.addProperty("bnkFlg", "Y"); |
||||
|
info.addProperty("yurRef", bankDO.getId().toString()); |
||||
|
bb1payopx1.add(info); |
||||
|
requestJson.getAsJsonObject("request").getAsJsonObject("body").add("bb1payopx1", bb1payopx1); |
||||
|
System.out.println(requestJson); |
||||
|
return null; |
||||
|
} |
||||
|
} |
@ -0,0 +1,369 @@ |
|||||
|
package com.win.bank.service.cmb; |
||||
|
|
||||
|
import java.io.*; |
||||
|
import java.math.BigInteger; |
||||
|
import java.net.HttpURLConnection; |
||||
|
import java.net.URL; |
||||
|
import java.net.URLEncoder; |
||||
|
import java.nio.charset.StandardCharsets; |
||||
|
import java.security.GeneralSecurityException; |
||||
|
import java.security.KeyStore; |
||||
|
import java.util.*; |
||||
|
|
||||
|
import javax.crypto.Cipher; |
||||
|
import javax.crypto.spec.IvParameterSpec; |
||||
|
import javax.crypto.spec.SecretKeySpec; |
||||
|
import javax.net.ssl.*; |
||||
|
|
||||
|
import org.bouncycastle.asn1.*; |
||||
|
import org.bouncycastle.crypto.CryptoException; |
||||
|
import org.bouncycastle.crypto.params.ECDomainParameters; |
||||
|
import org.bouncycastle.crypto.params.ECPrivateKeyParameters; |
||||
|
import org.bouncycastle.crypto.params.ECPublicKeyParameters; |
||||
|
import org.bouncycastle.crypto.params.ParametersWithID; |
||||
|
import org.bouncycastle.crypto.signers.SM2Signer; |
||||
|
import org.bouncycastle.jce.ECNamedCurveTable; |
||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider; |
||||
|
import org.bouncycastle.jce.spec.ECParameterSpec; |
||||
|
import org.bouncycastle.math.ec.ECPoint; |
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
|
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import com.fasterxml.jackson.databind.SerializationFeature; |
||||
|
import com.google.gson.Gson; |
||||
|
import com.google.gson.JsonArray; |
||||
|
import com.google.gson.JsonObject; |
||||
|
|
||||
|
/** |
||||
|
* 招商银行银企直联国密免前置/SaaS对接示例,本示例仅供参考,不保证各种异常场景运行,请勿直接使用,如有错漏请联系对接人员。运行时,请使用所获取的测试资源替换 用户编号、公私钥、对称密钥、服务商编号等信息。 |
||||
|
* |
||||
|
* @author cmb.firmbank |
||||
|
* @date 2023/7/20 |
||||
|
*/ |
||||
|
public class DcHelper { |
||||
|
|
||||
|
private static final int LENGTH_32 = 32; |
||||
|
private static final int USERID_LEN = 16; |
||||
|
private static final int CONNECT_TIMEOUT = 15000; |
||||
|
private static final int READ_TIMEOUT = 60000; |
||||
|
private static final int STATUS_OK = 200; |
||||
|
private static Base64.Encoder encoder = Base64.getEncoder(); |
||||
|
private static Base64.Decoder decoder = Base64.getDecoder(); |
||||
|
|
||||
|
// 请求URL
|
||||
|
private final String url; |
||||
|
// 企业网银用户号
|
||||
|
private final String uid; |
||||
|
// 国密算法向量,根据用户号生成
|
||||
|
private final byte[] userId; |
||||
|
// 算法,固定为国密算法
|
||||
|
private final String alg; |
||||
|
// 客户私钥
|
||||
|
private final byte[] privateKey; |
||||
|
// 银行公钥
|
||||
|
private final byte[] publicKey; |
||||
|
// 协商的对称密钥
|
||||
|
private final byte[] symKey; |
||||
|
|
||||
|
private static final Logger logger = LoggerFactory.getLogger(DcHelper.class); |
||||
|
|
||||
|
public DcHelper(String url, String uid, String privateKey, String publicKey, String symKey) { |
||||
|
this.url = url; |
||||
|
this.uid = uid; |
||||
|
this.userId = getUserId(uid); |
||||
|
this.alg = "SM"; |
||||
|
this.privateKey = decoder.decode(privateKey); |
||||
|
this.publicKey = decoder.decode(publicKey); |
||||
|
this.symKey = symKey.getBytes(StandardCharsets.UTF_8); |
||||
|
} |
||||
|
|
||||
|
public String sendRequest(String data, String funcode) throws IOException, CryptoException, GeneralSecurityException { |
||||
|
// 增加设备信息
|
||||
|
JsonObject requestJson = new Gson().fromJson(data, JsonObject.class); |
||||
|
// requestJson.getAsJsonObject("request").add("exthdr", deviceInfo.toJson());
|
||||
|
// 对请求报文做排序
|
||||
|
String source = recursiveKeySort(requestJson); |
||||
|
// 生成签名
|
||||
|
// byte[] signature = cmbSM2SignWithSM3(userId, privateKey, source.getBytes(StandardCharsets.UTF_8));
|
||||
|
// 替换签名字段
|
||||
|
// requestJson.getAsJsonObject("signature").addProperty("sigdat", new String(encoder.encode(signature),
|
||||
|
// StandardCharsets.UTF_8));
|
||||
|
|
||||
|
// 对数据进行对称加密
|
||||
|
// String request = requestJson.toString();
|
||||
|
// byte[] encryptRequest = cmbSM4Crypt(symKey, userId, request.getBytes(StandardCharsets.UTF_8), 1);
|
||||
|
// String encryptedRequest = new String(encoder.encode(encryptRequest), StandardCharsets.UTF_8);
|
||||
|
logger.debug(data); |
||||
|
// 发送请求
|
||||
|
HashMap<String, String> map = new HashMap<>(); |
||||
|
map.put("UID", uid); |
||||
|
map.put("ALG", alg); |
||||
|
map.put("DATA", URLEncoder.encode(data, StandardCharsets.UTF_8.displayName())); |
||||
|
// map.put("DATA", URLEncoder.encode(encryptedRequest, StandardCharsets.UTF_8.displayName()));
|
||||
|
map.put("FUNCODE", funcode); |
||||
|
String response = httpPost(url, map); |
||||
|
// logger.debug(response);
|
||||
|
printJson(data); |
||||
|
if (response.startsWith("CDCServer:")) { |
||||
|
throw new IOException("访问目标地址 " + url + " 失败:" + response); |
||||
|
} |
||||
|
|
||||
|
// 返回结果解密
|
||||
|
// response = new String((cmbSM4Crypt(symKey, userId, decoder.decode(response), 2)), StandardCharsets.UTF_8);
|
||||
|
|
||||
|
// 验证签名是否正确
|
||||
|
// JsonObject responseJson = new Gson().fromJson(response, JsonObject.class);
|
||||
|
// JsonObject signatureJson = responseJson.getAsJsonObject("signature");
|
||||
|
// String responseSignature = signatureJson.get("sigdat").getAsString();
|
||||
|
// signatureJson.addProperty("sigdat", "__signature_sigdat__");
|
||||
|
// responseJson.add("signature", signatureJson);
|
||||
|
// String responseSorted = recursiveKeySort(responseJson);
|
||||
|
// boolean verify = cmbSM2VerifyWithSM3(userId, publicKey, responseSorted.getBytes(StandardCharsets.UTF_8),
|
||||
|
// decoder.decode(responseSignature));
|
||||
|
// if (!verify) {
|
||||
|
// throw new IOException("响应报文的签名无效");
|
||||
|
// }
|
||||
|
printJson(response); |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
private static String recursiveKeySort(JsonObject json) { |
||||
|
StringBuilder appender = new StringBuilder(); |
||||
|
appender.append("{"); |
||||
|
Iterator<String> keys = new TreeSet<>(json.keySet()).iterator(); |
||||
|
boolean isFirstEle = true; |
||||
|
while (keys.hasNext()) { |
||||
|
if (!isFirstEle) { |
||||
|
appender.append(","); |
||||
|
} |
||||
|
String key = keys.next(); |
||||
|
Object val = json.get(key); |
||||
|
if (val instanceof JsonObject) { |
||||
|
appender.append("\"").append(key).append("\":"); |
||||
|
appender.append(recursiveKeySort((JsonObject)val)); |
||||
|
} else if (val instanceof JsonArray) { |
||||
|
JsonArray jarray = (JsonArray)val; |
||||
|
appender.append("\"").append(key).append("\":["); |
||||
|
boolean isFirstArrEle = true; |
||||
|
for (int i = 0; i < jarray.size(); i++) { |
||||
|
if (!isFirstArrEle) { |
||||
|
appender.append(","); |
||||
|
} |
||||
|
Object obj = jarray.get(i); |
||||
|
if (obj instanceof JsonObject) { |
||||
|
appender.append(recursiveKeySort((JsonObject)obj)); |
||||
|
} else { |
||||
|
appender.append(obj.toString()); |
||||
|
} |
||||
|
isFirstArrEle = false; |
||||
|
} |
||||
|
appender.append("]"); |
||||
|
} else { |
||||
|
String value = val.toString(); |
||||
|
appender.append("\"").append(key).append("\":").append(value); |
||||
|
} |
||||
|
isFirstEle = false; |
||||
|
} |
||||
|
appender.append("}"); |
||||
|
return appender.toString(); |
||||
|
} |
||||
|
|
||||
|
private static byte[] getUserId(String uid) { |
||||
|
return (uid + "0000000000000000").substring(0, USERID_LEN).getBytes(); |
||||
|
} |
||||
|
|
||||
|
private static String httpPost(String httpUrl, Map<String, String> param) throws IOException, GeneralSecurityException { |
||||
|
HttpURLConnection connection = null; |
||||
|
String result; |
||||
|
try { |
||||
|
URL url = new URL(httpUrl); |
||||
|
SSLContext sslcontext; |
||||
|
sslcontext = SSLContext.getInstance("SSL"); |
||||
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); |
||||
|
tmf.init((KeyStore)null); |
||||
|
X509TrustManager defaultTm = null; |
||||
|
for (TrustManager tm : tmf.getTrustManagers()) { |
||||
|
if (tm instanceof X509TrustManager) { |
||||
|
defaultTm = (X509TrustManager)tm; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
sslcontext.init(null, new TrustManager[] {defaultTm}, new java.security.SecureRandom()); |
||||
|
HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext.getSocketFactory()); |
||||
|
|
||||
|
connection = (HttpURLConnection)url.openConnection(); |
||||
|
connection.setRequestMethod("POST"); |
||||
|
connection.setConnectTimeout(CONNECT_TIMEOUT); |
||||
|
connection.setReadTimeout(READ_TIMEOUT); |
||||
|
connection.setInstanceFollowRedirects(true); |
||||
|
|
||||
|
connection.setDoOutput(true); |
||||
|
connection.setDoInput(true); |
||||
|
|
||||
|
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); |
||||
|
try (OutputStream os = connection.getOutputStream()) { |
||||
|
os.write(createLinkString(param).getBytes()); |
||||
|
if (connection.getResponseCode() != STATUS_OK) { |
||||
|
InputStream is = connection.getErrorStream(); |
||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); |
||||
|
StringBuilder sbf = new StringBuilder(); |
||||
|
String temp; |
||||
|
while ((temp = br.readLine()) != null) { |
||||
|
sbf.append(temp); |
||||
|
sbf.append("\r\n"); |
||||
|
} |
||||
|
|
||||
|
result = sbf.toString(); |
||||
|
br.close(); |
||||
|
is.close(); |
||||
|
} else { |
||||
|
InputStream is = connection.getInputStream(); |
||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); |
||||
|
StringBuilder sbf = new StringBuilder(); |
||||
|
String temp; |
||||
|
while ((temp = br.readLine()) != null) { |
||||
|
sbf.append(temp); |
||||
|
} |
||||
|
result = sbf.toString(); |
||||
|
br.close(); |
||||
|
is.close(); |
||||
|
} |
||||
|
} |
||||
|
} finally { |
||||
|
if (connection != null) { |
||||
|
connection.disconnect(); |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
private static String createLinkString(Map<String, String> params) { |
||||
|
ArrayList<String> keys = new ArrayList<>(params.keySet()); |
||||
|
Collections.sort(keys); |
||||
|
|
||||
|
StringBuilder prestr = new StringBuilder(); |
||||
|
for (int i = 0; i < keys.size(); i++) { |
||||
|
String key = keys.get(i); |
||||
|
String value = params.get(key); |
||||
|
if (i == keys.size() - 1) { |
||||
|
prestr.append(key).append("=").append(value); |
||||
|
} else { |
||||
|
prestr.append(key).append("=").append(value).append("&"); |
||||
|
} |
||||
|
} |
||||
|
return prestr.toString(); |
||||
|
} |
||||
|
|
||||
|
// 以下是加解密相关的函数
|
||||
|
|
||||
|
private static byte[] cmbSM2SignWithSM3(byte[] id, byte[] privkey, byte[] msg) throws IOException, CryptoException { |
||||
|
if (privkey == null || msg == null) { |
||||
|
throw new CryptoException("CMBSM2SignWithSM3 input error"); |
||||
|
} |
||||
|
ECPrivateKeyParameters privateKey = encodePrivateKey(privkey); |
||||
|
SM2Signer signer = new SM2Signer(); |
||||
|
ParametersWithID parameters = new ParametersWithID(privateKey, id); |
||||
|
signer.init(true, parameters); |
||||
|
signer.update(msg, 0, msg.length); |
||||
|
return decodeDERSignature(signer.generateSignature()); |
||||
|
} |
||||
|
|
||||
|
private static ECPrivateKeyParameters encodePrivateKey(byte[] value) { |
||||
|
BigInteger d = new BigInteger(1, value); |
||||
|
ECParameterSpec spec = ECNamedCurveTable.getParameterSpec("sm2p256v1"); |
||||
|
ECDomainParameters ecParameters = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(), spec.getH(), spec.getSeed()); |
||||
|
return new ECPrivateKeyParameters(d, ecParameters); |
||||
|
} |
||||
|
|
||||
|
private static byte[] decodeDERSignature(byte[] signature) throws IOException { |
||||
|
ASN1InputStream stream = new ASN1InputStream(new ByteArrayInputStream(signature)); |
||||
|
ASN1Sequence primitive = (ASN1Sequence)stream.readObject(); |
||||
|
Enumeration<ASN1Integer> enumeration = primitive.getObjects(); |
||||
|
BigInteger intR = enumeration.nextElement().getValue(); |
||||
|
BigInteger intS = enumeration.nextElement().getValue(); |
||||
|
byte[] bytes = new byte[LENGTH_32 * 2]; |
||||
|
byte[] r = format(intR.toByteArray()); |
||||
|
byte[] s = format(intS.toByteArray()); |
||||
|
System.arraycopy(r, 0, bytes, 0, LENGTH_32); |
||||
|
System.arraycopy(s, 0, bytes, LENGTH_32, LENGTH_32); |
||||
|
return bytes; |
||||
|
} |
||||
|
|
||||
|
private static byte[] format(byte[] value) { |
||||
|
if (value.length == LENGTH_32) { |
||||
|
return value; |
||||
|
} else { |
||||
|
byte[] bytes = new byte[LENGTH_32]; |
||||
|
if (value.length > LENGTH_32) { |
||||
|
System.arraycopy(value, value.length - LENGTH_32, bytes, 0, LENGTH_32); |
||||
|
} else { |
||||
|
System.arraycopy(value, 0, bytes, LENGTH_32 - value.length, value.length); |
||||
|
} |
||||
|
return bytes; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static byte[] cmbSM4Crypt(byte[] key, byte[] iv, byte[] input, int mode) throws GeneralSecurityException { |
||||
|
SecretKeySpec spec = new SecretKeySpec(key, "SM4"); |
||||
|
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); |
||||
|
Cipher cipher = Cipher.getInstance("SM4/CBC/PKCS7Padding", BouncyCastleProvider.PROVIDER_NAME); |
||||
|
cipher.init(mode, spec, ivParameterSpec); |
||||
|
return cipher.doFinal(input); |
||||
|
} |
||||
|
|
||||
|
private static boolean cmbSM2VerifyWithSM3(byte[] id, byte[] pubkey, byte[] msg, byte[] signature) throws IOException { |
||||
|
|
||||
|
if (pubkey == null || msg == null || signature == null) { |
||||
|
throw new IllegalArgumentException("CMBSM2VerifyWithSM3 input error"); |
||||
|
} |
||||
|
ECPublicKeyParameters publicKey = encodePublicKey(pubkey); |
||||
|
SM2Signer signer = new SM2Signer(); |
||||
|
ParametersWithID parameters = new ParametersWithID(publicKey, id); |
||||
|
signer.init(false, parameters); |
||||
|
signer.update(msg, 0, msg.length); |
||||
|
return signer.verifySignature(encodeDERSignature(signature)); |
||||
|
} |
||||
|
|
||||
|
private static ECPublicKeyParameters encodePublicKey(byte[] value) { |
||||
|
byte[] x = new byte[LENGTH_32]; |
||||
|
byte[] y = new byte[LENGTH_32]; |
||||
|
System.arraycopy(value, 1, x, 0, LENGTH_32); |
||||
|
System.arraycopy(value, LENGTH_32 + 1, y, 0, LENGTH_32); |
||||
|
BigInteger intX = new BigInteger(1, x); |
||||
|
BigInteger intY = new BigInteger(1, y); |
||||
|
ECParameterSpec spec = ECNamedCurveTable.getParameterSpec("sm2p256v1"); |
||||
|
ECPoint intQ = spec.getCurve().createPoint(intX, intY); |
||||
|
ECDomainParameters ecParameters = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(), spec.getH(), spec.getSeed()); |
||||
|
return new ECPublicKeyParameters(intQ, ecParameters); |
||||
|
} |
||||
|
|
||||
|
private static byte[] encodeDERSignature(byte[] signature) throws IOException { |
||||
|
byte[] r = new byte[LENGTH_32]; |
||||
|
byte[] s = new byte[LENGTH_32]; |
||||
|
System.arraycopy(signature, 0, r, 0, LENGTH_32); |
||||
|
System.arraycopy(signature, LENGTH_32, s, 0, LENGTH_32); |
||||
|
ASN1EncodableVector vector = new ASN1EncodableVector(); |
||||
|
vector.add(new ASN1Integer(new BigInteger(1, r))); |
||||
|
vector.add(new ASN1Integer(new BigInteger(1, s))); |
||||
|
return (new DERSequence(vector)).getEncoded(); |
||||
|
} |
||||
|
|
||||
|
private void printJson(String jsonStr) { |
||||
|
ObjectMapper mapper = new ObjectMapper(); |
||||
|
mapper.enable(SerializationFeature.INDENT_OUTPUT); |
||||
|
|
||||
|
try { |
||||
|
// 原始的JSON字符串
|
||||
|
// String jsonStr = "{\"name\": \"Alice\", \"age\": 30, \"city\": \"Beijing\"}";
|
||||
|
|
||||
|
// 格式化打印JSON字符串
|
||||
|
Object json = mapper.readValue(jsonStr, Object.class); |
||||
|
String formattedJsonStr = mapper.writeValueAsString(json); |
||||
|
// System.out.println(formattedJsonStr);
|
||||
|
logger.debug(formattedJsonStr); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,39 @@ |
|||||
|
package com.win.bank.service.cmb; |
||||
|
|
||||
|
import com.google.gson.JsonObject; |
||||
|
|
||||
|
/** |
||||
|
* 设备信息 |
||||
|
*/ |
||||
|
public class DeviceInfo { |
||||
|
|
||||
|
private String ipVal; |
||||
|
private String macVal; |
||||
|
private String cpuInfo; |
||||
|
private String computerName; |
||||
|
private String mainBoardId; |
||||
|
private String mainBoardName; |
||||
|
|
||||
|
public DeviceInfo(String ipVal, String macVal, String cpuInfo, String computerName, String mainBoardId, String mainBoardName) { |
||||
|
this.ipVal = ipVal; |
||||
|
this.macVal = macVal; |
||||
|
this.cpuInfo = cpuInfo; |
||||
|
this.computerName = computerName; |
||||
|
this.mainBoardId = mainBoardId; |
||||
|
this.mainBoardName = mainBoardName; |
||||
|
} |
||||
|
|
||||
|
public JsonObject toJson() { |
||||
|
JsonObject deviceInfo = new JsonObject(); |
||||
|
if (ipVal != null) { |
||||
|
deviceInfo.addProperty("ipType", ipVal.indexOf(':') != -1 ? "6" : "4"); |
||||
|
deviceInfo.addProperty("ipVal", ipVal); |
||||
|
} |
||||
|
deviceInfo.addProperty("macVal", macVal); |
||||
|
deviceInfo.addProperty("cpuInfo", cpuInfo); |
||||
|
deviceInfo.addProperty("cmpName", computerName); |
||||
|
deviceInfo.addProperty("mbId", mainBoardId); |
||||
|
deviceInfo.addProperty("mbMf", mainBoardName); |
||||
|
return deviceInfo; |
||||
|
} |
||||
|
} |
@ -0,0 +1,56 @@ |
|||||
|
package com.win.bank.service.demo; |
||||
|
|
||||
|
|
||||
|
import javax.xml.bind.annotation.XmlElement; |
||||
|
import javax.xml.bind.annotation.XmlRootElement; |
||||
|
|
||||
|
@XmlRootElement |
||||
|
public class Student { |
||||
|
|
||||
|
private String name; // 姓名
|
||||
|
private String sex; // 性别
|
||||
|
private int number; // 学号
|
||||
|
private String className; // 班级
|
||||
|
|
||||
|
public Student(){} |
||||
|
|
||||
|
public Student(String string, String string2, int i, String string3) { |
||||
|
this.name = string; |
||||
|
this.sex = string2; |
||||
|
this.className = string3; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@XmlElement(name = "name") |
||||
|
public String getName() { |
||||
|
return name; |
||||
|
} |
||||
|
public void setName(String name) { |
||||
|
this.name = name; |
||||
|
} |
||||
|
|
||||
|
@XmlElement(name = "sex") |
||||
|
public String getSex() { |
||||
|
return sex; |
||||
|
} |
||||
|
public void setSex(String sex) { |
||||
|
this.sex = sex; |
||||
|
} |
||||
|
|
||||
|
@XmlElement(name = "number") |
||||
|
public int getNumber() { |
||||
|
return number; |
||||
|
} |
||||
|
public void setNumber(int number) { |
||||
|
this.number = number; |
||||
|
} |
||||
|
|
||||
|
@XmlElement(name = "className") |
||||
|
public String getClassName() { |
||||
|
return className; |
||||
|
} |
||||
|
public void setClassName(String className) { |
||||
|
this.className = className; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,48 @@ |
|||||
|
package com.win.bank.service.demo; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.io.StringReader; |
||||
|
import java.io.StringWriter; |
||||
|
|
||||
|
import org.dom4j.Document; |
||||
|
import org.dom4j.io.OutputFormat; |
||||
|
import org.dom4j.io.SAXReader; |
||||
|
import org.dom4j.io.XMLWriter; |
||||
|
|
||||
|
/** |
||||
|
* @author admin |
||||
|
*/ |
||||
|
public class Test { |
||||
|
public static void main(String[] args) throws Exception { |
||||
|
Student st = new Student("张三", "男", 10001, "尖"); |
||||
|
String xml = XStreamUtil.marshal(st, Student.class); |
||||
|
System.out.println(xml); |
||||
|
// System.out.println(formatXML(xml));
|
||||
|
} |
||||
|
|
||||
|
public static String formatXML(String inputXML) throws Exception { |
||||
|
SAXReader reader = new SAXReader(); |
||||
|
Document document = reader.read(new StringReader(inputXML)); |
||||
|
String requestXML = null; |
||||
|
XMLWriter writer = null; |
||||
|
if (document != null) { |
||||
|
try { |
||||
|
StringWriter stringWriter = new StringWriter(); |
||||
|
OutputFormat format = new OutputFormat(" ", true); |
||||
|
writer = new XMLWriter(stringWriter, format); |
||||
|
writer.write(document); |
||||
|
writer.flush(); |
||||
|
requestXML = stringWriter.getBuffer().toString(); |
||||
|
} finally { |
||||
|
if (writer != null) { |
||||
|
try { |
||||
|
writer.close(); |
||||
|
} catch (IOException e) { |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return requestXML; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
package com.win.bank.service.demo; |
||||
|
|
||||
|
import java.io.StringWriter; |
||||
|
|
||||
|
import javax.xml.bind.JAXBContext; |
||||
|
import javax.xml.bind.JAXBException; |
||||
|
import javax.xml.bind.Marshaller; |
||||
|
|
||||
|
public class XStreamUtil { |
||||
|
public static String marshal(Object object, Class<?> clazz) throws JAXBException { |
||||
|
JAXBContext jaxbContext = JAXBContext.newInstance(clazz); |
||||
|
Marshaller marshaller = jaxbContext.createMarshaller(); |
||||
|
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); |
||||
|
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); |
||||
|
StringWriter writer = new StringWriter(); |
||||
|
marshaller.marshal(object, writer); |
||||
|
return writer.toString(); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
<?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.win.bank.dal.mysql.bank.BankMapper"> |
||||
|
|
||||
|
<!-- |
||||
|
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。 |
||||
|
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。 |
||||
|
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。 |
||||
|
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/ |
||||
|
--> |
||||
|
|
||||
|
</mapper> |
Loading…
Reference in new issue