1.背景说明:近期要做一个支付网关系统,原来的网关系统买的别人的,用的技术比较老webservice,由于现在springboot比较火,关键是很好用,开箱即用,所以决定在原来系统的基础上进行改造。
2.开始动手:
原来的代码结构,如下图:
3.第一步,结构调整,先添加一个新的springboot模块:
从官网http://projects.spring.io/spring-boot/快速生成一个springboot示例,然后在主pom中添加一个新的module,命名为mag-spring-boot,我用的是idea,然后导入添加的模块。
新的项目代码结构图,去除了多余的模块,把相应的依赖进行整理:
4.代码配置以此替换,springmvc的配置替换。
web.xml的配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>mag-facade-web</display-name>
<context-param>
<param-name>logbackConfigLocation</param-name>
<param-value>file:///opt/pay/config/basis/mag-tzt/mag-logback.xml</param-value>
</context-param>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>com.netfinworks.mag</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet>
<servlet-name>healthCheckDispatcher</servlet-name>
<servlet-class>com.netfinworks.common.monitor.web.servlet.HeathCheckDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>healthCheckDispatcher</servlet-name>
<url-pattern>/_health_check</url-pattern>
</servlet-mapping>
<!--param-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
<!-- listener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>
</listener>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
dispatch-servlet的配置:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
default-lazy-init="true" xmlns="http://www.springframework.org/schema/beans"
xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:task="http://www.springframework.org/schema/task"
xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"
default-autowire="byName">
<!-- 配置参数 -->
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file:///opt/pay/config/basis/mag-tzt/mag-app.properties</value>
<value>file:///opt/pay/config/basis/mag-tzt/mag-sftp-config.properties
</value>
</list>
</property>
</bean>
<!-- 收单网关 -->
<bean name="/gateway/receiveOrder.do" class="com.netfinworks.mag.web.controller.RecvOrder">
<property name="verifyService" ref="verifyService" />
<!-- property name="notifyService" ref="notifyService" / -->
<property name="contextUtil" ref="contextUtil" />
</bean>
<!-- 收单网关 投资通-->
<bean name="/gateway/receiveOrderTzt.do" class="com.netfinworks.mag.web.controller.RecvOrderTzt">
<property name="verifyService" ref="verifyService" />
<property name="contextUtil" ref="contextUtil" />
</bean>
<bean name="/sdk_gateway/sdk_receiveOrder.do" class="com.netfinworks.mag.web.controller.SDKRecvOrder">
<property name="verifyService" ref="verifyService" />
<!-- property name="notifyService" ref="notifyService" / -->
<property name="contextUtil" ref="contextUtil" />
</bean>
<!-- verifySign -->
<bean name="verifyService" class="com.netfinworks.mag.web.verify.VerifyService">
<property name="md5KeyService" ref="md5KeyService"></property>
<property name="rsaService" ref="rsaService"></property>
<property name="uesFacade" ref="uesFacade"></property>
</bean>
<bean name="md5KeyService" class="com.netfinworks.mag.web.sign.MD5KeyService">
</bean>
<bean name="rsaService" class="com.netfinworks.mag.web.sign.RSAService">
</bean>
<!-- ma -->
<bean name="maQueryService" class="com.netfinworks.mag.ext.service.MaQueryService">
<property name="memberFacade" ref="memberFacade" />
<property name="accountFacade" ref="accountFacade" />
<property name="merchantFacade" ref="merchantFacade" />
<property name="bankAccountFacade" ref="bankAccountFacade" />
<property name="udinghuoPartnerId" value="${udinghuo.partnerid}" />
<property name="verifyFacade" ref="verifyFacade" />
</bean>
<!-- 鉴权系统 -->
<jaxws:client id="authControlService"
serviceClass="com.netfinworks.authsys.api.AuthControlService"
address="${authsys.ws.url}/authControlFacadeAddress" />
<!-- 鉴权相关 -->
<bean name="authSysAuthControlService" class="com.netfinworks.mag.ext.service.AuthSysAuthControlService">
<property name="authControlService" ref="authControlService" />
</bean>
<!-- cac卡账务中心-->
<bean name="cacService" class="com.netfinworks.mag.ext.service.CacService">
<property name="iBankAccountFacade" ref="iBankAccountFacade" />
</bean>
<jaxws:client id="iBankAccountFacade"
serviceClass="com.netfinworks.cac.service.facade.IBankAccountFacade"
address="${cac.ws.url}/BankAccountFacade" />
<!-- ues -->
<jaxws:client id="uesFacade"
serviceClass="com.netfinworks.ues.services.UesRemoteService" address="${ma.ws.url}/UesRemoteService" />
<!-- ma -->
<jaxws:client id="memberFacade"
serviceClass="com.netfinworks.ma.service.facade.IMemberFacade"
address="${ma.ws.url}/MemberFacade" />
<jaxws:client id="accountFacade"
serviceClass="com.netfinworks.ma.service.facade.IAccountFacade"
address="${ma.ws.url}/AccountFacade" />
<jaxws:client id="merchantFacade"
serviceClass="com.netfinworks.ma.service.facade.IMerchantFacade"
address="${ma.ws.url}/MerchantFacade" />
<jaxws:client id="bankAccountFacade"
serviceClass="com.netfinworks.ma.service.facade.IBankAccountFacade"
address="${ma.ws.url}/BankAccountFacade" />
<jaxws:client id="verifyFacade"
serviceClass="com.netfinworks.ma.service.facade.IVerifyFacade"
address="${ma.ws.url}/VerifyFacade" />
<!-- cashier -->
<bean id="cashierQueryService" class="com.netfinworks.mag.ext.service.CashierQueryService">
<property name="cashierFacade" ref="cashierFacade"></property>
</bean>
<jaxws:client id="cashierFacade"
serviceClass="com.netfinworks.cashier.facade.api.CashierFacade"
address="${cashier.ws.url}/cashierService">
</jaxws:client>
<!-- site -->
<bean id="siteQueryService" class="com.netfinworks.mag.ext.service.SiteQueryService">
<property name="siteFacade" ref="siteFacade"></property>
</bean>
<jaxws:client id="siteFacade"
serviceClass="com.netfinworks.site.facade.api.SiteFacade"
address="${site.ws.url}/siteService">
</jaxws:client>
<!-- trade -->
<bean id="tradeService" class="com.netfinworks.mag.ext.service.TradeService">
<property name="tradeFacade" ref="tradeFacade"></property>
<property name="cashierQueryService" ref="cashierQueryService"></property>
<property name="maQueryService" ref="maQueryService"></property>
<property name="netbankSuccessUrl" value="${netbank.success.url}"></property>
<property name="whiteChannelCodeMap" value="${white.channel.code}"></property>
</bean>
<jaxws:client id="tradeFacade"
serviceClass="com.netfinworks.tradeservice.facade.api.TradeProcessFacade"
address="${trade.ws.url}/tradeProcessFacade">
</jaxws:client>
<http-conf:conduit name=".*/tradeProcessFacade">
<http-conf:client ConnectionTimeout="25000"
ReceiveTimeout="30000" />
</http-conf:conduit>
<!-- trade query -->
<bean id="tradeQueryService" class="com.netfinworks.mag.ext.service.TradeQueryService">
<property name="tradeQueryFacade" ref="tradeQueryFacade"></property>
</bean>
<jaxws:client id="tradeQueryFacade"
serviceClass="com.netfinworks.tradeservice.facade.api.TradeQueryFacade"
address="${trade.ws.url}/tradeQueryFacade">
</jaxws:client>
<!-- trade-site query -->
<bean id="tradeSiteQueryService" class="com.netfinworks.mag.ext.service.TradeSiteQueryService">
<property name="tradeSiteQueryFacade" ref="tradeSiteQueryFacade"></property>
</bean>
<jaxws:client id="tradeSiteQueryFacade"
serviceClass="com.netfinworks.tradeservice.facade.api.TradeQueryFacade"
address="${trade-query.ws.url}/tradeQueryFacade">
</jaxws:client>
<!-- acs -->
<bean id="acsQueryService" class="com.netfinworks.mag.ext.service.AcsQueryService">
<property name="authFacade" ref="authFacade"></property>
<property name="merchantCofFacade" ref="merchantCofFacade"></property>
</bean>
<jaxws:client id="authFacade"
serviceClass="com.netfinworks.acs.service.facade.ApiAuthorizationFacade"
address="${acs.ws.url}/apiAuth" />
<jaxws:client id="merchantCofFacade"
serviceClass="com.netfinworks.acs.service.facade.MerchantConfigurationFacade"
address="${acs.ws.url}/merchantCof" />
<!-- 统一凭证 -->
<bean id="voucherService" class="com.netfinworks.mag.ext.service.VoucherService">
<property name="voucherFacade" ref="voucherFacade"></property>
</bean>
<jaxws:client id="voucherFacade"
serviceClass="com.netfinworks.voucher.service.facade.VoucherFacade"
address="${voucher.ws.url}/voucherFacade" />
<!-- Fos -->
<bean id="fosService" class="com.netfinworks.mag.ext.service.FosService">
<property name="fosFacade" ref="fosFacade"></property>
<property name="fundoutFacade" ref="fundoutFacade"></property>
<property name="paymentFacade" ref="paymentFacade"></property>
</bean>
<jaxws:client id="fosFacade"
serviceClass="com.netfinworks.fos.service.facade.WithdrawalFacade"
address="${fos.ws.url}/WithdrawalFacade">
</jaxws:client>
<jaxws:client id="fundoutFacade"
serviceClass="com.netfinworks.fos.service.facade.FundoutFacade"
address="${fos.ws.url}/FundoutFacade">
</jaxws:client>
<jaxws:client id="paymentFacade"
serviceClass="com.netfinworks.fos.service.facade.PaymentFacade"
address="${fos.ws.url}/PaymentFacade">
</jaxws:client>
<!-- pfs -->
<bean id="pfsService" class="com.netfinworks.mag.ext.service.PfsService">
<property name="fundsControlFacade" ref="fundsControlFacade"></property>
</bean>
<jaxws:client id="fundsControlFacade"
serviceClass="com.netfinworks.pfs.service.payment.FundsControlFacade"
address="${pfs-payment.ws.url}/fundsControlFacade">
</jaxws:client>
<bean id="cardBinValidateService" class="com.netfinworks.mag.ext.service.CardBinValidateService">
<property name="cardBinValidateFacade" ref="cardBinValidateFacade"></property>
</bean>
<jaxws:client id="cardBinValidateFacade"
serviceClass="com.netfinworks.pfs.service.basis.cardbin.CardBinValidateFacade"
address="${pfs-basis.ws.url}/cardBinValidateService">
</jaxws:client>
<bean id="bankInfoService" class="com.netfinworks.mag.ext.service.BankInfoService">
<property name="bankInfoFacade" ref="bankInfoFacade"></property>
</bean>
<jaxws:client id="bankInfoFacade"
serviceClass="com.netfinworks.pfs.service.manager.basis.baseinfo.BankInfoFacade"
address="${pfs-manager.ws.url}/bankInfoService">
</jaxws:client>
<bean id="branchQueryService" class="com.netfinworks.mag.ext.service.BranchQueryService">
<property name="branchQueryFacade" ref="branchQueryFacade"></property>
</bean>
<jaxws:client id="branchQueryFacade"
serviceClass="com.netfinworks.pfs.service.basis.branchinfo.BranchQueryFacade"
address="${pfs-basis.ws.url}/branchQueryService">
</jaxws:client>
<!-- sars -->
<bean id="sarsService" class="com.netfinworks.mag.ext.service.SarsService">
<property name="sarsClientService" ref="sarsClientService"></property>
</bean>
<bean name="sarsEngineContext" id="sarsEngineContext"
class="com.netfinworks.sars.rules.engine.EngineContext">
<property name="checkPoints">
<util:list>
<value>CP101</value>
</util:list>
</property>
<property name="ruleServerWSDL" value="${sars.address}/PolicyRemoteService?wsdl" />
<property name="sarsServerWsdl" value="${sars.address}/RmsRemoteService?wsdl" />
<!-- Sars server MQ conf -->
<property name="sarsServerMqEnvironment">
<props>
<prop key="java.naming.factory.initial">${netfinworksmq.java.naming.factory.initial}</prop>
<prop key="java.naming.provider.url">${netfinworksmq.java.naming.provider.url}</prop>
<prop key="java.naming.security.principal">${netfinworksmq.java.naming.security.principal}
</prop>
<prop key="java.naming.security.credentials">${netfinworksmq.java.naming.security.credentials}
</prop>
</props>
</property>
<property name="sarsServerMqDestination" value="${jms.sars.server.destination}" />
<!-- Sars client Venus conf -->
</bean>
<bean id="sarsClientService" class="com.netfinworks.sars.client.api.SarsServiceFactory"
factory-method="newSarsService">
<constructor-arg ref="sarsEngineContext" />
</bean>
<jaxws:client id="uesRemoteService"
serviceClass="com.netfinworks.ues.services.UesRemoteService" address="${ues.ws.url}/UesRemoteService" />
<bean id="uesClient" class="com.netfinworks.ues.UesClient">
<property name="uesRemoteService" ref="uesRemoteService" />
</bean>
<bean class="com.netfinworks.mag.ext.service.UesService" name="uesService"
id="uesService">
<property name="uesClient" ref="uesClient"></property>
</bean>
<!-- service route -->
<bean name="serviceBase" class="com.netfinworks.mag.service.base.MagServiceBase">
<property name="maQueryService" ref="maQueryService"></property>
<property name="voucherService" ref="voucherService"></property>
<property name="tradeService" ref="tradeService"></property>
<property name="cashierQueryService" ref="cashierQueryService"></property>
<property name="tradeQueryService" ref="tradeQueryService"></property>
<property name="authSysAuthControlService" ref="authSysAuthControlService"></property>
<property name="sarsService" ref="sarsService"></property>
<property name="cacService" ref="cacService"></property>
<property name="acsQueryService" ref="acsQueryService"></property>
<property name="uesService" ref="uesService"></property>
</bean>
<bean id="sftpService" class="com.netfinworks.mag.ext.service.SftpService">
<property name="sftpHost" value="${sftp.host}" />
<property name="sftpPort" value="${sftp.port}" />
<property name="sftpUserName" value="${sftp.username}" />
<property name="sftpPassword" value="${sftp.password}" />
<property name="sftpRootDir" value="${sftp.rootdir}" />
</bean>
<!-- add by niubl 20160325 start 新增收单网关接口 -->
<bean
class="com.netfinworks.mag.service.route.chanpay.CJT_CreateBatchInstantTrade"></bean>
<bean
class="com.netfinworks.mag.service.route.chanpay.CJT_CreateInstantTrade">
<property name="acsQueryService" ref="acsQueryService"></property>
<property name="userId" value="${externalSettlement.chanpay.userId}" />
<property name="pid" value="${externalSettlement.chanpay.PID}" />
<property name="accountType" value="${externalSettlement.chanpay.accountType}" />
</bean>
<bean
class="com.netfinworks.mag.service.route.chanpay.CJT_CreateWapBatchInstantTrade"></bean>
<bean
class="com.netfinworks.mag.service.route.chanpay.CJT_CreateWapInstantTrade"></bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_CreateRefund"></bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_EveryDayTradeFile">
<property name="sftpService" ref="sftpService" />
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_FeeTradeFile">
<property name="sftpService" ref="sftpService" />
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_RefundTradeFile">
<property name="sftpService" ref="sftpService" />
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_EveryDayTradeOwnFile">
<property name="sftpService" ref="sftpService" />
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_FeeTradeOwnFile">
<property name="sftpService" ref="sftpService" />
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_RefundTradeOwnFile">
<property name="sftpService" ref="sftpService" />
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_MerSourceTradeOwnFile">
<property name="sftpService" ref="sftpService" />
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_GetPayChannel"></bean>
<bean
class="com.netfinworks.mag.service.route.chanpay.CJT_MerSourceTradeFile"></bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_QueryTrade">
<property name="tradeQueryService" ref="tradeQueryService"></property>
<property name="fosService" ref="fosService"></property>
</bean>
<bean
class="com.netfinworks.mag.service.route.chanpay.CJT_SDKCreateInstantTrade"></bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_ViewReceipt">
<property name="downloadReceiptURL" value="${download.receipt.url}"></property>
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_PaymentToCardService">
<property name="fosService" ref="fosService"></property>
<property name="uesService" ref="uesService"></property>
<property name="acsQueryService" ref="acsQueryService"></property>
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_GetBindingCards">
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_UnbindCard">
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_OrderWithdraw">
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_CreateQuickPayment">
<property name="uesService" ref="uesService"></property>
<property name="acsQueryService" ref="acsQueryService"></property>
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_QuickPaymentConfirm">
<property name="acsQueryService" ref="acsQueryService"></property>
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_WapQuickPayment">
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_Withdraw">
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_CreateSettle">
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_EnsureTrade">
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_CreateBalanceTransfer">
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_RealTimePaymentService">
<property name="fosService" ref="fosService"></property>
<property name="uesService" ref="uesService"></property>
<property name="acsQueryService" ref="acsQueryService"></property>
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_RealTimeReceiveService">
<property name="uesService" ref="uesService"></property>
<property name="acsQueryService" ref="acsQueryService"></property>
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_QueryPayService">
<property name="tradeQueryService" ref="tradeQueryService"></property>
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_QuickEnsureTrade">
</bean>
<bean class="com.netfinworks.mag.service.route.chanpay.CJT_BatchRealTimePayment">
<property name="fosService" ref="fosService"></property>
<property name="uesService" ref="uesService"></property>
<property name="acsQueryService" ref="acsQueryService"></property>
</bean>
<!-- add by niubl 20160325 end -->
<bean class="com.netfinworks.mag.service.route.GetPayChannelService"></bean>
<bean class="com.netfinworks.mag.service.route.InstantTradeService"></bean>
<bean class="com.netfinworks.mag.service.route.InstantTradeForAppService"></bean>
<bean class="com.netfinworks.mag.service.route.EnsureTradeService"></bean>
<bean class="com.netfinworks.mag.service.route.BatchPayService"></bean>
<bean class="com.netfinworks.mag.service.route.BatchPayForAppService"></bean>
<bean class="com.netfinworks.mag.service.route.SettleService"></bean>
<bean class="com.netfinworks.mag.service.route.RefundService"></bean>
<bean class="com.netfinworks.mag.service.route.PrepayService"></bean>
<bean class="com.netfinworks.mag.service.route.PrepayWithholdService"></bean>
<bean class="com.netfinworks.mag.service.route.QueryTradeService">
<property name="tradeQueryService" ref="tradeQueryService"></property>
</bean>
<bean class="com.netfinworks.mag.service.route.ChangeTradeAmountService"></bean>
<bean class="com.netfinworks.mag.service.route.CancelTradeService"></bean>
<bean class="com.netfinworks.mag.service.route.WithdrawalService"></bean>
<bean class="com.netfinworks.mag.service.route.BatchWithdrawalService"></bean>
<bean class="com.netfinworks.mag.service.route.MarginRechargeService"></bean>
<bean class="com.netfinworks.mag.service.route.QueryMarginChangesService"></bean>
<bean class="com.netfinworks.mag.service.route.BalanceTransferService"></bean>
<bean class="com.netfinworks.mag.service.route.DownloadReceipt2Image">
<property name="downloadReceiptURL" value="${download.receipt.url}"></property>
</bean>
<bean class="com.netfinworks.mag.service.route.PaymentToCardService">
<property name="fosService" ref="fosService"></property>
<property name="uesService" ref="uesService"></property>
<property name="acsQueryService" ref="acsQueryService"></property>
</bean>
<bean class="com.netfinworks.mag.service.route.FrozenFundsService"></bean>
<bean class="com.netfinworks.mag.service.route.UnfreezeFundsService"></bean>
<bean id="contextUtil" class="com.netfinworks.mag.service.base.SpringContextUtil"></bean>
<!-- 投资通新增接口bean注入 -->
<bean class="com.netfinworks.mag.service.route.invest.AuthWithoutSmsService"></bean>
<bean class="com.netfinworks.mag.service.route.invest.SmsAuthBindCardConfirmService"></bean>
<bean class="com.netfinworks.mag.service.route.invest.SmsAuthBindCardService"></bean>
<bean class="com.netfinworks.mag.service.route.invest.SmsBindCardReqService"></bean>
<bean class="com.netfinworks.mag.service.route.invest.SmsBindCardConfirmService"></bean>
<bean class="com.netfinworks.mag.service.route.invest.UnifiedQueryOrderService"></bean>
<bean class="com.netfinworks.mag.service.route.invest.UrgentOrderWithdrawService"></bean>
<bean class="com.netfinworks.mag.service.route.invest.UnifiedOrderRefundService"></bean>
<bean class="com.netfinworks.mag.service.route.invest.AuthBindCardInfoQueryService"></bean>
<bean class="com.netfinworks.mag.service.route.invest.SmsAuthBindCardResendService"></bean>
<bean class="com.netfinworks.mag.service.route.invest.BindCardModifyStateService"></bean>
<!-- 定时任务 -->
<task:scheduled-tasks>
<task:scheduled ref="acsTask" method="refresh" cron="${task.cron}" />
</task:scheduled-tasks>
<bean id="acsTask" class="com.netfinworks.mag.service.trigger.AcsTask">
<property name="acsQueryService" ref="acsQueryService"></property>
</bean>
<!--
<bean id="createStatementFileTask"
class="com.netfinworks.mag.service.trigger.CreateStatementFileTask">
<property name="tradeSiteQueryService" ref="tradeSiteQueryService" />
<property name="sftpService" ref="sftpService" />
<property name="voucherService" ref="voucherService" />
<property name="maQueryService" ref="maQueryService" />
<property name="uesService" ref="uesService" />
<property name="acsQueryService" ref="acsQueryService"></property>
</bean>
<task:scheduled-tasks>
<task:scheduled ref="createStatementFileTask" method="createStatementFile4PayWater"
cron="${sftp.task.corn}" />
<task:scheduled ref="createStatementFileTask" method="createStatementFile4RefundWater"
cron="${sftp.task.corn}" />
</task:scheduled-tasks>
-->
</beans>
applicationContext.xml的配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
default-autowire="byName">
<context:annotation-config/>
<!-- <context:property-placeholder location="file:///opt/pay/config/basis/inf/mag/mag-app.properties" ignore-unresolvable="true" />-->
<import resource="classpath:META-INF/spring/*-bean.xml" />
</beans>
首先在mag-spring-boot模块中加入spring-boot-starter-web依赖,具体该依赖都包含哪些自动配置,请参考一下链接:https://zhuanlan.zhihu.com/p/28580443?group_id=881552221710458881,支持springmvc和web开发等。具体的springboot的启动流程详解请参考链接:http://www.cnblogs.com/xinzhao/p/5551828.html,在目录resources下面新建目录MATE-INFO,再新建文件spring.factories,配置需要加载的类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.netfinworks.mag.config.WebConfig
类WebConfig继承了WebmvcConfigurerAdapter来加载springmvc配置:
package com.netfinworks.mag.config;
import ch.qos.logback.access.servlet.TeeFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.catalina.filters.RemoteIpFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import java.util.ArrayList;
import java.util.List;
/**
* WEB配置类
*
* @author zhangyongji
*/
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
/**
* 对应web.xml
* -> <servlet-name>dispatcher</servlet-name>
* -> <filter-name>CharacterEncodingFilter</filter-name>
*
* @return
*/
@Bean
public FilterRegistrationBean encodingFilter() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter("UTF-8", true);
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(encodingFilter);
List<String> list = new ArrayList<>();
list.add("/");
filterRegistrationBean.setUrlPatterns(list);
return filterRegistrationBean;
}
/**
* 对应applicationContext.xml里面的配置
*
* @return
*/
@Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/static");
resolver.setSuffix(".html");
resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class);
return resolver;
}
/**
* 注册试图解析器
*
* @param registry
*/
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.viewResolver(getViewResolver());
}
/**
* Remote ip filter remote ip filter.
*
* @return the remote ip filter
*/
@Bean
public RemoteIpFilter remoteIpFilter() {
return new RemoteIpFilter();
}
/**
* Tee filter tee filter.
*
* @return the tee filter
*/
@Bean
@ConditionalOnProperty(prefix = "server.tomcat.accesslog", name = "debug", havingValue = "true")
public TeeFilter teeFilter() {
//复制请求响应流,用于打印调试日志
return new TeeFilter();
}
/**
* Object mapper object mapper.
*
* @return the object mapper
*/
@Bean
public ObjectMapper objectMapper() {
return new JsonMapper();
}
/**
* Http message converter http message converter.
*
* @return the http message converter
*/
@Bean
public HttpMessageConverter httpMessageConverter() {
return new MappingJackson2HttpMessageConverter(this.objectMapper());
}
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false) // 系统对外暴露的 URL 不会识别和匹配 .* 后缀
.setUseTrailingSlashMatch(true); // 系统不区分 URL 的最后一个字符是否是斜杠 /
}
@Override
public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) {
// 等价于<mvc:default-servlet-handler />, 对静态资源文件的访问, 将无法 mapping 到 Controller 的 path 交给 default servlet handler 处理
configurer.enable();
}
/**
* Validator local validator factory bean.
*
* @return the local validator factory bean
*/
@Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
localValidatorFactoryBean.setProviderClass(org.hibernate.validator.HibernateValidator.class);
return localValidatorFactoryBean;
}
/**
* Gets method validation post processor.
*
* @return the method validation post processor
*/
@Bean
public MethodValidationPostProcessor getMethodValidationPostProcessor() {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setValidator(validator());
return processor;
}
/**
* Container customizer embedded servlet container customizer.
*
* @return the embedded servlet container customizer
*/
@Bean
@ConditionalOnProperty(prefix = "server.tomcat.accesslog", name = "debug", havingValue = "true")
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new ContainerAccessLogCustomizer("logback-access.xml");
}
/**
* 这个地方要重新注入一下资源文件,不然不会注入资源的,也没有注入requestHandlerMappping,相当于xml配置的
* <!--swagger资源配置-->
* <mvc:resources location="classpath:/META-INF/resources/" mapping="swagger-ui.html"/>
* <mvc:resources location="classpath:/META-INF/resources/webjars/" mapping="/webjars/**"/>
* 不知道为什么,这也是spring boot的一个缺点(菜鸟觉得的)
* <p>
* //* @param registry
*/
//@Override
//public void addResourceHandlers(ResourceHandlerRegistry registry) {
// registry.addResourceHandler("swagger-ui.html")
// .addResourceLocations("classpath:/META-INF/resources/");
// registry.addResourceHandler("/webjars*")
// .addResourceLocations("classpath:/META-INF/resources/webjars/");
//}
@Bean(name = "/gateway/dptRoute.do")
public GatewayRoute getGatewayRoute() {
return new GatewayRoute();
}
}
默认错误页面,如果在下图目录下有500页面,则会加载自定义的错误页面;主要启动类,自动配置,启动定时任务,引入dubbo配置:
入口类GatewayRoute,用SpringContextUtil获取带注解@serviceRoute的类,eg:@ServiceRoute(name = "DPT_HSB_API_ALEVE_FILE"):即通过前台传过来的service名称路由到不同的类进行处理。
package com.netfinworks.mag.config;
import com.meidusa.fastjson.JSON;
import com.netfinworks.common.lang.StringUtil;
import com.netfinworks.mag.constant.RequestConstant;
import com.netfinworks.mag.domain.base.PubBaseRequestDto;
import com.netfinworks.mag.domain.base.PubBaseResponseDto;
import com.netfinworks.mag.enums.ServiceKind;
import com.netfinworks.mag.exception.CommonDefinedException;
import com.netfinworks.mag.exception.ErrorCodeException;
import com.netfinworks.mag.exception.ErrorCodeException.CommonException;
import com.netfinworks.mag.helper.RequestHelper;
import com.netfinworks.mag.service.base.IMagService;
import com.netfinworks.mag.service.base.SpringContextUtil;
import com.netfinworks.mag.service.job.Jobs;
import com.netfinworks.mag.util.tools.AuniXSS;
import com.netfinworks.mag.util.tools.MagCore;
import com.netfinworks.mag.web.verify.VerifyService;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class GatewayRoute extends AbstractController {
private static final Logger logger = LoggerFactory
.getLogger(GatewayRoute.class);
private final Charset BASIC_REQUEST_ENCODING = Charset.forName("UTF-8");
@Autowired
private VerifyService verifyService;
@Autowired
private Jobs jobs;
@Autowired
private SpringContextUtil contextUtil;
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
PubBaseResponseDto pubBaseResponseDto = new PubBaseResponseDto();
PubBaseRequestDto pubBaseRequestDto = new PubBaseRequestDto();
try {
logger.info(">>..行业统一网关接入");
Map<?, ?> parameters = request.getParameterMap();
if (logger.isInfoEnabled()) {
logger.info(request.getMethod()
+ ", GatewayRoute original request:"
+ JSON.toJSONString(parameters));
}
logger.info(">>..公共请求参数 request{}", parameters);
if (parameters == null || parameters.isEmpty() == true) {
// 什么参数都没有
throw CommonDefinedException.REQUIRED_FIELD_NOT_EXIST;
}
Charset charset = getEncoding(request);
logger.info(">>..charset={}", charset);
Map<String, String> formattedParameters = new HashMap<String, String>(
parameters.size());
for (Map.Entry<?, ?> entry : parameters.entrySet()) {
if (entry.getValue() == null
|| Array.getLength(entry.getValue()) == 0) {
formattedParameters.put((String) entry.getKey(), null);
} else {
if (HttpMethod.GET.name().equals(request.getMethod())) {
formattedParameters.put(
(String) entry.getKey(),
new String(((String) Array.get(
entry.getValue(), 0))
.getBytes(BASIC_REQUEST_ENCODING),
charset));
} else {
formattedParameters
.put((String) entry.getKey(), URLDecoder
.decode((String) Array.get(
entry.getValue(), 0),
charset.name()));
}
}
}
if (logger.isInfoEnabled()) {
logger.info("GatewayRoute original request format:"
+ JSON.toJSONString(formattedParameters));
}
String serviceName = getServiceName(formattedParameters);
logger.info(">>..接口名称 serviceName={}", serviceName);
IMagService service = (IMagService) contextUtil
.getServiceByAnnoName(serviceName);
// 转换为基础对象
pubBaseRequestDto = RequestHelper.convertBase(formattedParameters);
logger.info(">>..转换为基础对象 PubBaseRequestDto={}", pubBaseRequestDto);
// 验签
verify(pubBaseRequestDto, charset, formattedParameters);
// 防XSS攻击,去掉“<”和“>”
formattedParameters = auniXSS(formattedParameters);
// 获取Ip
String ip = getIpFromReq(request);
formattedParameters.put(RequestConstant.IP, ip);
// 分接口处理
pubBaseResponseDto = service.process(formattedParameters);
// 电子账户密码是否已设置可以通过接口查询账户是否已设置密码5004查询。如果已设置密码,可以直接引导客户进入提现页面
if (service.equals("DPT_HSB_API_PIN_SETUP") || service.equals("DPT_HSB_API_WITHHOLDING")) {
Map<String, String> modelMap = new HashMap<String, String>();
modelMap.put("CardNbr",formattedParameters.get("CardNbr"));
modelMap.put("MerId",formattedParameters.get("MerId"));
modelMap.put("InputCharset",formattedParameters.get("InputCharset"));
modelMap.put("TradeDate",formattedParameters.get("TradeDate"));
modelMap.put("TradeTime",formattedParameters.get("TradeTime"));
modelMap.put("CoinstCode",formattedParameters.get("CoinstCode"));
modelMap.put("CoinstChannel",formattedParameters.get("CoinstChannel"));
modelMap.put("ESBSource",formattedParameters.get("ESBSource"));
modelMap.put("Sign","");
modelMap.put("SignType","RSA");
modelMap.put("TradeMemo","");
modelMap.put("RetCode",RequestConstant.SYSTEM_SUCCESS);
modelMap.put("RetMsg","交易成功");
String respMsg = this.sign(pubBaseResponseDto);
modelMap = (Map) JSON.parse(respMsg);
modelMap.put("InputCharset", "UTF-8");
String resetPwdSurl = formattedParameters.get("ResetPwdSurl");
String resetPwdFurl = formattedParameters.get("ResetPwdFurl");
//if (pubBaseResponseDto.getAcceptStatus().equalsIgnoreCase(RequestConstant.AcceptStatus.SUCCESS)) {
// modelMap.put("AcceptStatus", RequestConstant.AcceptStatus.SUCCESS);
// return new ModelAndView(new RedirectView(resetPwdSurl), modelMap);
//} else {
// modelMap.put("AcceptStatus", RequestConstant.AcceptStatus.FAIL);
// modelMap.put("Status", RequestConstant.AcceptStatus.FAIL);
// return new ModelAndView(new RedirectView(resetPwdFurl), modelMap);
//}
//交易描述字段存放的返回的from表单数据
if (null != pubBaseResponseDto && null != pubBaseResponseDto.getTradeMemo() && pubBaseResponseDto.getTradeMemo().trim().startsWith("<form")) {
logger.info("==== 页面FORM表单跳转数据 ====" + pubBaseResponseDto.getTradeMemo());
// chrome兼容
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(pubBaseResponseDto.getTradeMemo());
}
}
//交易描述字段存放的返回的文件名称,扩展字段存放下载文件字符
if ("DPT_HSB_API_EVE_FILE".equals(serviceName) || "DPT_HSB_API_ALEVE_FILE".equals(serviceName)) {
if (null != pubBaseResponseDto && null != pubBaseResponseDto.getTradeMemo()) {
文件名编码,解决乱码问题
String fileName = pubBaseResponseDto.getTradeMemo();
encodeURIComponent(fileName);
setFileDownloadHeader(response, fileName);
文件下载
OutputStream out = response.getOutputStream();
out.write((byte[]) pubBaseResponseDto.getExpandAttribute().get("files"));
}
}
if (pubBaseResponseDto != null) {
// 统一处理
respSuccess(response, pubBaseRequestDto, pubBaseResponseDto);
}
} catch (Exception e) {
e.printStackTrace();
if (e instanceof ErrorCodeException) {
logger.error("ErrorCode:" + ((ErrorCodeException) e).getErrorCode() + ";"
+ "ErrorMsg:" + ((ErrorCodeException) e).getErrorMsg()
+ ";Memo:" + ((ErrorCodeException) e).getMemo(), e);
respError(response, (ErrorCodeException) e, ((ErrorCodeException) e).getMemo(), pubBaseRequestDto, pubBaseResponseDto);
} else {
logger.error("系统错误", e);
respError(response, CommonDefinedException.SYSTEM_ERROR, "系统错误", pubBaseRequestDto, pubBaseResponseDto);
}
return null;
}
return null;
}
/**
* 验签
*
* @param pubBaseRequestDto
* @param charset
* @param formattedParameters
* @throws CommonException
*/
private void verify(PubBaseRequestDto pubBaseRequestDto, Charset charset,
Map<String, String> formattedParameters) throws CommonException {
boolean verifyResult = false;
String signContent = MagCore.createLinkString(
MagCore.paraFilter(formattedParameters), false);
if (logger.isInfoEnabled()) {
logger.info("verify signature: { content:" + signContent
+ ", signMsg:" + pubBaseRequestDto.getSign() + "}");
}
verifyResult = verifyService.verify(pubBaseRequestDto.getMerId(), signContent, pubBaseRequestDto.getSign(),
charset.name(), pubBaseRequestDto.getSignType());
if (!verifyResult) {
// 验签未通过
logger.error("ErrorCode:" + CommonDefinedException.ILLEGAL_SIGN.getErrorCode() + ";"
+ "ErrorMsg:" + CommonDefinedException.ILLEGAL_SIGN.getErrorMsg()
+ ";request dosen't pass verify.");
throw CommonDefinedException.ILLEGAL_SIGN;
}
if (logger.isDebugEnabled()) {
logger.debug("invoke verify end:" + verifyResult);
}
}
private Charset getEncoding(HttpServletRequest request)
throws CommonException {
Charset utf8Charset = Charset.forName("UTF-8");
String inputCharset = request.getParameter(RequestConstant.INPUT_CHARSET);
if (StringUtil.isEmpty(inputCharset)) {
CommonException exp = CommonDefinedException.INPUT_CHARSET_ERROR;
exp.setMemo("编码类型不能为空");
throw exp;
}
if ("UTF-8".equalsIgnoreCase(inputCharset)) {
return utf8Charset;
}
CommonException exp = CommonDefinedException.INPUT_CHARSET_ERROR;
exp.setMemo("无法识别编码类型:" + inputCharset);
throw exp;
}
/**
* 取得service并验证支付方式
*
* @param parameters
* @return
* @throws Exception
*/
private String getServiceName(Map<String, String> parameters)
throws Exception {
String serviceName = parameters.get(RequestConstant.SERVICE);
String MERID = parameters.get(RequestConstant.MER_ID);
if (StringUtil.isEmpty(MERID)) {
CommonException exp = CommonDefinedException.REQUIRED_FIELD_NOT_EXIST;
exp.setMemo("合作者身份ID");
throw exp;
} else if (MERID.length() > 32) {
CommonException exp = CommonDefinedException.FIELD_LENGTH_EXCEEDS_LIMIT;
exp.setMemo("合作者身份ID");
throw exp;
}
if (StringUtil.isEmpty(serviceName)) {
CommonException exp = CommonDefinedException.REQUIRED_FIELD_NOT_EXIST;
exp.setMemo("接口名称");
throw exp;
}
ServiceKind service = ServiceKind.getByCode(serviceName);
if (service == null) {
throw CommonDefinedException.ILLEGAL_SERVICE;
}
return serviceName;
}
/**
* 统一成功处理
*
* @param response
* @param req
* @param resp
* @throws Exception
*/
private void respSuccess(HttpServletResponse response, PubBaseRequestDto req, PubBaseResponseDto resp)
throws Exception {
resp.setMerId(req.getMerId());
resp.setTradeDate(req.getTradeDate());
resp.setTradeTime(req.getTradeTime());
resp.setCoinstChannel(req.getCoinstChannel());
resp.setCoinstCode(req.getCoinstCode());
resp.setESBSource(req.getESBSource());
resp.setAcceptStatus(RequestConstant.AcceptStatus.SUCCESS);
resp.setRetCode(RequestConstant.SYSTEM_SUCCESS);
resp.setRetMsg("交易成功");
resp.setInputCharset("UTF-8");
response.setHeader("content-type", "text/html;charset=UTF-8");
response.setHeader("Access-Control-Allow-Origin", "*");
String respMes = this.sign(resp);
response.getWriter().write(respMes);
}
/**
* 统一错误处理
*
* @param response
* @param e
* @param memo
* @throws Exception
*/
private void respError(HttpServletResponse response, ErrorCodeException e,
String memo, PubBaseRequestDto req, PubBaseResponseDto resp) throws Exception {
resp.setMerId(req.getMerId());
resp.setTradeDate(req.getTradeDate());
resp.setTradeTime(req.getTradeTime());
resp.setCoinstChannel(req.getCoinstChannel());
resp.setCoinstCode(req.getCoinstCode());
resp.setESBSource(req.getESBSource());
resp.setAcceptStatus(RequestConstant.AcceptStatus.FAIL);
resp.setInputCharset("UTF-8");
resp.setRetCode(e.getErrorCode());
resp.setRetMsg(e.getErrorMsg());
resp.setTradeMemo(StringUtils.isNotEmpty(memo) ? memo : "");
response.setCharacterEncoding("UTF-8");
response.setHeader("content-type", "text/html;charset=UTF-8");
response.setHeader("Access-Control-Allow-Origin", "*");
String respMes = this.sign(resp);
response.getWriter().write(respMes);
}
private Map<String, String> auniXSS(Map<String, String> reqMap) {
Map<String, String> result = new HashMap<String, String>(reqMap.size());
for (Map.Entry<String, String> entry : reqMap.entrySet()) {
if (entry.getValue() == null) {
result.put((String) entry.getKey(), null);
} else {
String value = AuniXSS.encode(entry.getValue());
result.put((String) entry.getKey(), value);
}
}
return result;
}
/**
* 返回参数加签
*
* @param resp
* @return
* @throws Exception
* @throws Exception
*/
private String sign(PubBaseResponseDto resp) throws Exception {
Map<String, String> map = new HashMap<String, String>();
String respJsonSrc = JSON.toJSONString(resp);
JSONObject respJson = JSONObject.fromObject(respJsonSrc);
Iterator<String> it = respJson.keys();
while (it.hasNext()) {
String k = it.next();
String v = respJson.getString(k);
map.put(k, v);
}
String charset = map.get("InputCharset");
if (StringUtils.isEmpty(charset)) {
charset = "UTF-8";
}
String signType = "RSA";
String signKey = jobs.queryMerPrivateKey().getPrivateKey();
Map<String, String> result = MagCore.buildRequestPara(map, signType,
signKey, charset);
return JSON.toJSONString(result);
}
/**
* 从HttpServletRequest对象中获取客户端的真实ip并打印到前置网关日志
*
* @param request
*/
private String getIpFromReq(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
ip = ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
return ip;
}
/**
* <pre>
* 浏览器下载文件时需要在服务端给出下载的文件名,当文件名是ASCII字符时没有问题
* 当文件名有非ASCII字符时就有可能出现乱码
*
* 这里的实现方式参考这篇文章
* http://blog.robotshell.org/2012/deal-with-http-header-encoding-for-file-download/
*
* 最终设置的response header是这样:
*
* Content-Disposition: attachment;
* filename="encoded_text";
* filename*=utf-8''encoded_text
*
* 其中encoded_text是经过RFC 3986的“百分号URL编码”规则处理过的文件名
* </pre>
* @param response
* @param filename
* @return
*/
public static void setFileDownloadHeader(HttpServletResponse response, String filename) {
String headerValue = "attachment;";
headerValue += " filename=\"" + encodeURIComponent(filename) + "\";";
headerValue += " filename*=utf-8''" + encodeURIComponent(filename);
response.setHeader("Content-Disposition", headerValue);
}
/**
* <pre>
* 符合 RFC 3986 标准的“百分号URL编码”
* 在这个方法里,空格会被编码成%20,而不是+
* 和浏览器的encodeURIComponent行为一致
* </pre>
*
* @param value
* @return
*/
public static String encodeURIComponent(String value) {
try {
return URLEncoder.encode(value, "UTF-8").replaceAll("\\+", "%20");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
}
service类,需要加上@ServiceRoute(name = "DPT_HSB_API_ALEVE_FILE")@Configuration注解:
package com.netfinworks.mag.service;
import com.alibaba.fastjson.JSON;
import com.chanpay.ppd.dpt.api.mch.dto.QueryMchAuthRequest;
import com.chanpay.ppd.dpt.api.mch.dto.QueryMchAuthResponse;
import com.chanpay.ppd.dpt.api.mch.facade.IMchAuthFacade;
import com.netfinworks.mag.annotation.ServiceRoute;
import com.netfinworks.mag.constant.RequestConstant;
import com.netfinworks.mag.domain.AlEveFileRequest;
import com.netfinworks.mag.domain.base.PubBaseResponseDto;
import com.netfinworks.mag.exception.CommonDefinedException;
import com.netfinworks.mag.exception.ErrorCodeException.CommonException;
import com.netfinworks.mag.helper.RequestHelper;
import com.netfinworks.mag.helper.WebServiceHelper;
import com.netfinworks.mag.service.base.MagServiceBase;
import com.netfinworks.mag.util.SftpService;
import com.netfinworks.mag.util.StreamUtils;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.io.InputStream;
import java.util.Map;
/**
* Created by jiji on 2017/7/15.
*/
@ServiceRoute(name = "DPT_HSB_API_ALEVE_FILE")
@Configuration
public class AlEveFileService extends MagServiceBase {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private SftpService sftpService;
@Autowired
private IMchAuthFacade mchAuthFacade;
@Autowired
private WebServiceHelper webServiceHelper;
public PubBaseResponseDto process(Map<String, String> paraMap) throws Exception {
getLogger().info("==== 全流水文件接口 ====");
PubBaseResponseDto response = this.handle(paraMap);
return response;
}
private PubBaseResponseDto handle(Map<String, String> paraMap) throws Exception {
String cardProdNo = null;
PubBaseResponseDto response = new PubBaseResponseDto();
AlEveFileRequest request = (AlEveFileRequest) RequestHelper.convertFromMap(paraMap);
/**参数校验 -- 校验一些必输信息 以及字段长度限制*/
validaPara(request);
QueryMchAuthRequest queryMchAuthRequest = new QueryMchAuthRequest();
queryMchAuthRequest.setMerId(request.getMerId());
webServiceHelper.requestWrapper(queryMchAuthRequest);
QueryMchAuthResponse queryMchAuthResponse = mchAuthFacade.queryMchAuth(queryMchAuthRequest);
if (null != queryMchAuthResponse && null != queryMchAuthResponse.getMchAuthList() && queryMchAuthResponse.getMchAuthList().size() > 0) {
if (StringUtils.isNotEmpty(queryMchAuthResponse.getMchAuthList().get(0).getCardProdNo())) {
cardProdNo = queryMchAuthResponse.getMchAuthList().get(0).getCardProdNo();
} else {
CommonException exp = CommonDefinedException.CARD_PRODNO_EXP;
exp.setMemo("商户配置异常,请配置产品编码");
throw exp;
}
} else {
CommonException exp = CommonDefinedException.CARD_PRODNO_EXP;
exp.setMemo("商户配置异常,请配置产品编码");
throw exp;
}
Map<String, byte[]> map = new HashedMap();
logger.info("交易明细流水文件接口请求参数:" + JSON.toJSONString(request));
String files = sftpService.getFiles(request.getMerId(), request.getEveDate());
String fileName = RequestConstant.HS_BANK_CODE + "-" + "ALEVE" + cardProdNo + "-" + request.getEveDate();
if (StringUtils.isNotEmpty(files)) {
InputStream inputStream = StreamUtils.StringTOInputStream(files);
byte[] bi = StreamUtils.inputStream2Byte(inputStream);
response.setTradeMemo(fileName);
map.put("files", bi);
response.setExpandAttribute(map);
} else {
CommonException exp = CommonDefinedException.FILE_IS_NOT_EXISTS;
exp.setMemo("文件不存在");
throw exp;
}
return response;
}
}
定时任务类:
package com.netfinworks.mag.service.job;
import com.alibaba.fastjson.JSONObject;
import com.chanpay.ppd.dpt.api.mch.dto.MchAuth;
import com.chanpay.ppd.dpt.api.mch.dto.QueryMchAuthRequest;
import com.chanpay.ppd.dpt.api.mch.dto.QueryMchAuthResponse;
import com.chanpay.ppd.dpt.api.mch.facade.IMchAuthFacade;
import com.chanpay.ppd.dpt.api.security.dto.QueryMerPublicKeyRequest;
import com.chanpay.ppd.dpt.api.security.dto.QueryMerPublicKeyResponse;
import com.chanpay.ppd.dpt.api.security.dto.QueryPayPrivateKeyRequest;
import com.chanpay.ppd.dpt.api.security.dto.QueryPayPrivateKeyResponse;
import com.chanpay.ppd.dpt.api.security.facade.ISecurityFacade;
import com.netfinworks.mag.constant.RequestConstant;
import com.netfinworks.mag.exception.CommonDefinedException;
import com.netfinworks.mag.exception.ErrorCodeException.CommonException;
import com.netfinworks.mag.helper.WebServiceHelper;
import com.netfinworks.mag.util.tools.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
@Configuration
@ConfigurationProperties(prefix = "job.task")
public class Jobs {
private static Logger logger = LoggerFactory.getLogger(Jobs.class);
public static final String CACHE_NAME = "merInfo";
public final static long TOW_Hours = 2 * 60 * 60 * 1000;
//public final static long TOW_Hours = 60 * 1000;
@Autowired
private ISecurityFacade securityFacade;
@Autowired
private WebServiceHelper webServiceHelper;
@Autowired
private IMchAuthFacade mchAuthFacade;
/**
* fixedRate就是每多少分钟一次,不论你业务执行花费了多少时间,我都是1分钟执行1次
*/
@Scheduled(fixedRate = TOW_Hours)
@CacheEvict(value = CACHE_NAME, allEntries = true)
public void fixedRateJob() {
System.out.println(">>fixedRate执行,清空缓存...." + DateUtils.getDateStr());
}
@Cacheable(value = CACHE_NAME)
public QueryMerPublicKeyResponse queryMerPublicKey(String merId) throws Exception {
QueryMchAuthRequest queryMchAuthRequest = new QueryMchAuthRequest();
queryMchAuthRequest.setMerId(merId);
webServiceHelper.requestWrapper(queryMchAuthRequest);
QueryMchAuthResponse queryMchAuthResponse = mchAuthFacade.queryMchAuth(queryMchAuthRequest);
if (null != queryMchAuthResponse && null != queryMchAuthResponse.getMchAuthList() && queryMchAuthResponse.getMchAuthList().size() > 0) {
for (MchAuth mchAuth : queryMchAuthResponse.getMchAuthList()) {
if (mchAuth.getIsOpen().equals(RequestConstant.MchAuthStatus.N)) {
throw CommonDefinedException.ILLEGAL_ACCESS_SWITCH_SYSTEM;
}
}
} else {
//请求的服务,不在商户配置中
throw CommonDefinedException.ILLEGAL_ACCESS_SWITCH_SYSTEM;
}
QueryMerPublicKeyRequest queryMerPublicKeyRequest = new QueryMerPublicKeyRequest();
webServiceHelper.requestWrapper(queryMerPublicKeyRequest);
queryMerPublicKeyRequest.setMerId(merId);
logger.info("调用查询商户公钥配置请求对象:" + JSONObject.toJSONString(queryMerPublicKeyRequest));
QueryMerPublicKeyResponse queryMerPublicKeyResponse = securityFacade.queryMerPublicKey(queryMerPublicKeyRequest);
logger.info("调用查询商户公钥配置响应对象:" + (null != queryMerPublicKeyResponse ? JSONObject.toJSONString(queryMerPublicKeyResponse) : queryMerPublicKeyResponse));
// 商户服务
if (null != queryMerPublicKeyResponse && queryMerPublicKeyResponse.getRespCode().equals(RequestConstant.DPTFacade.SUCCESS)) {
return queryMerPublicKeyResponse;
} else {
CommonException exp = CommonDefinedException.QUERY_MER_KEY_EXP;
exp.setMemo("查询商户公钥失败");
throw exp;
}
}
@Cacheable(value = CACHE_NAME)
public QueryPayPrivateKeyResponse queryMerPrivateKey() throws Exception {
QueryPayPrivateKeyRequest queryPayPrivateKeyRequest = new QueryPayPrivateKeyRequest();
webServiceHelper.requestWrapper(queryPayPrivateKeyRequest);
logger.info("调用查询商户私钥配置请求对象:" + JSONObject.toJSONString(queryPayPrivateKeyRequest));
QueryPayPrivateKeyResponse queryPayPrivateKeyResponse = securityFacade.queryPayPrivateKey(queryPayPrivateKeyRequest);
logger.info("调用查询商户私钥配置响应对象:" + (null != queryPayPrivateKeyResponse ? JSONObject.toJSONString(queryPayPrivateKeyResponse) : queryPayPrivateKeyResponse));
// 商户服务
if (null != queryPayPrivateKeyResponse && queryPayPrivateKeyResponse.getRespCode().equals(RequestConstant.DPTFacade.SUCCESS)) {
return queryPayPrivateKeyResponse;
} else {
CommonException exp = CommonDefinedException.QUERY_MER_KEY_EXP;
exp.setMemo("查询商户私钥失败");
throw exp;
}
}
}
相关的主要类差不多就介绍完了,然后就可以启动调试了。
相关其他配置文件的动态打包部署可以参考链接:https://github.com/jiji87432/springboot-dubbox
启动相关脚本:https://github.com/jiji87432/nginx_sh