diff --git a/pjcloud-auth/src/main/java/com/bsd/pjcloud/auth/support/handler/PjcloudAuthenticationFailureEventHandler.java b/pjcloud-auth/src/main/java/com/bsd/pjcloud/auth/support/handler/PjcloudAuthenticationFailureEventHandler.java index 6afa4d62c..4ef8f487c 100644 --- a/pjcloud-auth/src/main/java/com/bsd/pjcloud/auth/support/handler/PjcloudAuthenticationFailureEventHandler.java +++ b/pjcloud-auth/src/main/java/com/bsd/pjcloud/auth/support/handler/PjcloudAuthenticationFailureEventHandler.java @@ -59,115 +59,117 @@ import java.util.concurrent.TimeUnit; @RequiredArgsConstructor public class PjcloudAuthenticationFailureEventHandler implements AuthenticationFailureHandler { - private static final MappingJackson2HttpMessageConverter errorHttpResponseConverter = new MappingJackson2HttpMessageConverter(); + private static final MappingJackson2HttpMessageConverter errorHttpResponseConverter = new MappingJackson2HttpMessageConverter(); - private final StringRedisTemplate redisTemplate; + private final StringRedisTemplate redisTemplate; - private final ApplicationEventPublisher publisher; + private final ApplicationEventPublisher publisher; - private final KeyStrResolver tenantKeyStrResolver; + private final KeyStrResolver tenantKeyStrResolver; - private final RemoteUserService userService; + private final RemoteUserService userService; - /** - * Called when an authentication attempt fails. - * @param request the request during which the authentication attempt occurred. - * @param response the response. - * @param exception the exception which was thrown to reject the authentication - * request. - */ - @Override - @SneakyThrows - public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, - AuthenticationException exception) { - String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE); - exception.printStackTrace(); - log.info("登录失败,异常:{}", exception.getLocalizedMessage()); + /** + * Called when an authentication attempt fails. + * + * @param request the request during which the authentication attempt occurred. + * @param response the response. + * @param exception the exception which was thrown to reject the authentication + * request. + */ + @Override + @SneakyThrows + public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, + AuthenticationException exception) { + String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE); + exception.printStackTrace(); + log.info("登录失败,异常:|{}|stack:|{}|", exception.getLocalizedMessage(), exception.getStackTrace()); - // 密码模式记录错误信息 - if (OAuth2ParameterNames.PASSWORD.equals(grantType)) { - String username = request.getParameter(OAuth2ParameterNames.USERNAME); + // 密码模式记录错误信息 + if (OAuth2ParameterNames.PASSWORD.equals(grantType)) { + String username = request.getParameter(OAuth2ParameterNames.USERNAME); - // 密码错误记录错误次数 (TOC用户不记录) - String header = WebUtils.getRequest().getHeader(SecurityConstants.HEADER_TOC); - if (exception instanceof OAuth2AuthenticationException - && !SecurityConstants.HEADER_TOC_YES.equals(header)) { - recordLoginFailureTimes(username); - } + // 密码错误记录错误次数 (TOC用户不记录) + String header = WebUtils.getRequest().getHeader(SecurityConstants.HEADER_TOC); + if (exception instanceof OAuth2AuthenticationException + && !SecurityConstants.HEADER_TOC_YES.equals(header)) { + recordLoginFailureTimes(username); + } - // 记录登录失败错误信息 - sendFailureEventLog(request, exception, username); - } + // 记录登录失败错误信息 + sendFailureEventLog(request, exception, username); + } - // 写出错误信息 - sendErrorResponse(request, response, exception); - } + // 写出错误信息 + sendErrorResponse(request, response, exception); + } - /** - * 记录失败日志 - * @param request HttpServletRequest - * @param exception 错误日志 - * @param username 用户名 - */ - private void sendFailureEventLog(HttpServletRequest request, AuthenticationException exception, String username) { - SysLogDTO logVo = SysLogUtils.getSysLog(); - logVo.setTitle("登录失败"); - logVo.setLogType(LogTypeEnum.ERROR.getType()); - logVo.setException(exception.getLocalizedMessage()); - // 发送异步日志事件 - String startTimeStr = request.getHeader(CommonConstants.REQUEST_START_TIME); - if (StrUtil.isNotBlank(startTimeStr)) { - Long startTime = Long.parseLong(startTimeStr); - Long endTime = System.currentTimeMillis(); - logVo.setTime(endTime - startTime); - } - String header = request.getHeader(HttpHeaders.AUTHORIZATION); - String clientId = WebUtils.extractClientId(header).orElse(null); - logVo.setServiceId(clientId); - logVo.setCreateBy(username); - logVo.setTenantId(Long.parseLong(tenantKeyStrResolver.key())); - publisher.publishEvent(new SysLogEvent(logVo)); - } + /** + * 记录失败日志 + * + * @param request HttpServletRequest + * @param exception 错误日志 + * @param username 用户名 + */ + private void sendFailureEventLog(HttpServletRequest request, AuthenticationException exception, String username) { + SysLogDTO logVo = SysLogUtils.getSysLog(); + logVo.setTitle("登录失败"); + logVo.setLogType(LogTypeEnum.ERROR.getType()); + logVo.setException(exception.getLocalizedMessage()); + // 发送异步日志事件 + String startTimeStr = request.getHeader(CommonConstants.REQUEST_START_TIME); + if (StrUtil.isNotBlank(startTimeStr)) { + Long startTime = Long.parseLong(startTimeStr); + Long endTime = System.currentTimeMillis(); + logVo.setTime(endTime - startTime); + } + String header = request.getHeader(HttpHeaders.AUTHORIZATION); + String clientId = WebUtils.extractClientId(header).orElse(null); + logVo.setServiceId(clientId); + logVo.setCreateBy(username); + logVo.setTenantId(Long.parseLong(tenantKeyStrResolver.key())); + publisher.publishEvent(new SysLogEvent(logVo)); + } - /** - * 记录登录失败此处,如果操作阈值 调用接口锁定用户 - * @param username username - */ - private void recordLoginFailureTimes(String username) { - String key = String.format("%s:%s:%s", tenantKeyStrResolver.key(), CacheConstants.LOGIN_ERROR_TIMES, username); - Long deltaTimes = ParamResolver.getLong("LOGIN_ERROR_TIMES", 5L); - Long times = redisTemplate.opsForValue().increment(key); + /** + * 记录登录失败此处,如果操作阈值 调用接口锁定用户 + * + * @param username username + */ + private void recordLoginFailureTimes(String username) { + String key = String.format("%s:%s:%s", tenantKeyStrResolver.key(), CacheConstants.LOGIN_ERROR_TIMES, username); + Long deltaTimes = ParamResolver.getLong("LOGIN_ERROR_TIMES", 5L); + Long times = redisTemplate.opsForValue().increment(key); - // 自动过期时间 - Long deltaTime = ParamResolver.getLong("DELTA_TIME", 1L); - redisTemplate.expire(key, deltaTime, TimeUnit.HOURS); + // 自动过期时间 + Long deltaTime = ParamResolver.getLong("DELTA_TIME", 1L); + redisTemplate.expire(key, deltaTime, TimeUnit.HOURS); - if (deltaTimes <= times) { - userService.lockUser(username); - } - } + if (deltaTimes <= times) { + userService.lockUser(username); + } + } - private void sendErrorResponse(HttpServletRequest request, HttpServletResponse response, - AuthenticationException exception) throws IOException { - ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response); - httpResponse.setStatusCode(HttpStatus.UNAUTHORIZED); - String errorMessage; + private void sendErrorResponse(HttpServletRequest request, HttpServletResponse response, + AuthenticationException exception) throws IOException { + ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response); + httpResponse.setStatusCode(HttpStatus.UNAUTHORIZED); + String errorMessage; - if (exception instanceof OAuth2AuthenticationException) { - OAuth2AuthenticationException authorizationException = (OAuth2AuthenticationException) exception; - errorMessage = StrUtil.isBlank(authorizationException.getError().getDescription()) - ? authorizationException.getError().getErrorCode() - : authorizationException.getError().getDescription(); + if (exception instanceof OAuth2AuthenticationException) { + OAuth2AuthenticationException authorizationException = (OAuth2AuthenticationException) exception; + errorMessage = StrUtil.isBlank(authorizationException.getError().getDescription()) + ? authorizationException.getError().getErrorCode() + : authorizationException.getError().getDescription(); - this.errorHttpResponseConverter.write( - R.failed(authorizationException.getError().getErrorCode(), errorMessage), - MediaType.APPLICATION_JSON, httpResponse); + this.errorHttpResponseConverter.write( + R.failed(authorizationException.getError().getErrorCode(), errorMessage), + MediaType.APPLICATION_JSON, httpResponse); - } - else { - errorMessage = exception.getLocalizedMessage(); - this.errorHttpResponseConverter.write(R.failed(errorMessage), MediaType.APPLICATION_JSON, httpResponse); - } - } + } else { + errorMessage = exception.getLocalizedMessage(); + this.errorHttpResponseConverter.write(R.failed(errorMessage), MediaType.APPLICATION_JSON, httpResponse); + } + } } diff --git a/pjcloud-common/pjcloud-common-core/src/main/java/com/bsd/pjcloud/common/core/constant/CacheConstants.java b/pjcloud-common/pjcloud-common-core/src/main/java/com/bsd/pjcloud/common/core/constant/CacheConstants.java index 95ecb3d15..231c3263a 100644 --- a/pjcloud-common/pjcloud-common-core/src/main/java/com/bsd/pjcloud/common/core/constant/CacheConstants.java +++ b/pjcloud-common/pjcloud-common-core/src/main/java/com/bsd/pjcloud/common/core/constant/CacheConstants.java @@ -138,5 +138,7 @@ public interface CacheConstants { String THIRDPARTY_ZY_MER_TOKEN = "thirdparty:zy:mer_token"; + String THIRDPARTY_ZY_SELF_TOKEN = "thirdparty:zy:self_token:"; + /* ************************************* end 第三方对接相关 end ************************************* */ } diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/constant/order/HardOrderTypeEnum.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/constant/order/HardOrderTypeEnum.java index be3fb28f9..147d06fa9 100644 --- a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/constant/order/HardOrderTypeEnum.java +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/constant/order/HardOrderTypeEnum.java @@ -38,4 +38,10 @@ public enum HardOrderTypeEnum { return refundList.contains(type); } + public static List getExternalCodes() { + return List.of( + HardOrderTypeEnum.FOREIGN_TICKET.type, + HardOrderTypeEnum.STRIDE_DEPT.type + ); + } } diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/order/HardOrderDto.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/order/HardOrderDto.java index 6ab0fe157..be29ec0a7 100644 --- a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/order/HardOrderDto.java +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/dto/order/HardOrderDto.java @@ -31,6 +31,8 @@ public class HardOrderDto extends HardOrderEntity implements BaseIsIncludeTreeIn private LocalDateTime[] payTimeList; + private List orderTypeCodes; + /** * 是否查询购物车列表 */ diff --git a/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardZyCardSyncVo.java b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardZyCardSyncVo.java new file mode 100644 index 000000000..f111dcf3b --- /dev/null +++ b/pjcloud-hardware/pjcloud-hardware-api/src/main/java/com/bsd/pjcloud/hard/api/vo/order/HardZyCardSyncVo.java @@ -0,0 +1,48 @@ +package com.bsd.pjcloud.hard.api.vo.order; + +import lombok.Data; + +@Data +public class HardZyCardSyncVo { + + /** + * 总人数 + */ + private Long totalNum; + + /** + * 总金额 + */ + private Long totalMoney; + + /** + * 年总人数 + */ + private Long totalNumYear; + + /** + * 年总金额 + */ + private Long totalMoneyYear; + + /** + * 月总人数 + */ + private Long totalNumMonth; + + /** + * 月总金额 + */ + private Long totalMoneyMonth; + + /** + * 月总人数 + */ + private Long totalNumDay; + + /** + * 月总金额 + */ + private Long totalMoneyDay; + +} diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/order/HardOrderTotalController.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/order/HardOrderTotalController.java index 3f49abf34..3a722a141 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/order/HardOrderTotalController.java +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/controller/order/HardOrderTotalController.java @@ -13,11 +13,13 @@ import com.bsd.pjcloud.common.core.util.R; import com.bsd.pjcloud.common.log.annotation.SysLog; import com.bsd.pjcloud.hard.api.constant.HardTypeEnum; import com.bsd.pjcloud.hard.api.constant.order.HardOrderStatusEnum; +import com.bsd.pjcloud.hard.api.constant.order.HardOrderTypeEnum; import com.bsd.pjcloud.hard.api.dto.order.HardDeptTotalDto; import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto; import com.bsd.pjcloud.hard.api.vo.order.HardDeptTotalVo; import com.bsd.pjcloud.hard.api.vo.order.HardOrderCsVo; import com.bsd.pjcloud.hard.api.vo.order.HardOrderSbVo; +import com.bsd.pjcloud.hard.api.vo.order.HardZyCardSyncVo; import com.bsd.pjcloud.hard.service.HardOrderTotalService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; @@ -45,6 +47,19 @@ public class HardOrderTotalController { private final HardOrderTotalService HardOrderTotalService; + /* ************************************* start 远程调用 start ************************************* */ + + @PostMapping("/zy-card-sync") + @Operation(summary = "正元本地一卡通交易数据同步") + public R zyCardSync() { + HardOrderDto dto = new HardOrderDto(); + dto.setOrderStatusCodes(HardOrderStatusEnum.getPayPrice()); + dto.setOrderTypeCodes(HardOrderTypeEnum.getExternalCodes()); + return R.ok(HardOrderTotalService.totalYearMonthDay(dto)); + } + + /* ************************************* end 远程调用 end ************************************* */ + @PostMapping("/page-list-sb") @Operation(summary = "设备交易记录") public R> pageListSb(@ParameterObject Page page, @RequestBody HardOrderDto dto) { diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/mapper/order/HardOrderMapper.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/mapper/order/HardOrderMapper.java index 5bbbd35ba..fc2ca74f9 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/mapper/order/HardOrderMapper.java +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/mapper/order/HardOrderMapper.java @@ -11,10 +11,7 @@ import com.bsd.pjcloud.hard.api.dto.order.HardOrderSumAndCountDto; import com.bsd.pjcloud.hard.api.entity.HardManagerEntity; import com.bsd.pjcloud.hard.api.entity.order.HardAfterSaleEntity; import com.bsd.pjcloud.hard.api.entity.order.HardOrderEntity; -import com.bsd.pjcloud.hard.api.vo.order.HardOrderCsVo; -import com.bsd.pjcloud.hard.api.vo.order.HardOrderSbVo; -import com.bsd.pjcloud.hard.api.vo.order.HardOrderSumAndCountVo; -import com.bsd.pjcloud.hard.api.vo.order.HardOrderVo; +import com.bsd.pjcloud.hard.api.vo.order.*; import com.github.yulichang.wrapper.MPJLambdaWrapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -98,4 +95,6 @@ public interface HardOrderMapper extends PjcloudBaseMapper { List listCs(@Param("dto") HardOrderDto dto); List sumAndCount(@Param("dto") HardOrderSumAndCountDto dto); + + HardZyCardSyncVo totalYearMonthDay(@Param("dto") HardOrderDto hardOrderDto); } \ No newline at end of file diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardOrderTotalService.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardOrderTotalService.java index 6a605938c..8ec4f0f38 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardOrderTotalService.java +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/HardOrderTotalService.java @@ -6,6 +6,7 @@ import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto; import com.bsd.pjcloud.hard.api.vo.order.HardDeptTotalVo; import com.bsd.pjcloud.hard.api.vo.order.HardOrderCsVo; import com.bsd.pjcloud.hard.api.vo.order.HardOrderSbVo; +import com.bsd.pjcloud.hard.api.vo.order.HardZyCardSyncVo; import java.util.List; @@ -20,4 +21,6 @@ public interface HardOrderTotalService { List listCs(HardOrderDto dto); List pageListDept(HardDeptTotalDto dto); + + HardZyCardSyncVo totalYearMonthDay(HardOrderDto dto); } diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOrderTotalServiceImpl.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOrderTotalServiceImpl.java index 93acc7c1e..26442ff10 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOrderTotalServiceImpl.java +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOrderTotalServiceImpl.java @@ -8,16 +8,14 @@ import com.bsd.pjcloud.admin.api.entity.SysDept; import com.bsd.pjcloud.admin.api.feign.RemoteDeptService; import com.bsd.pjcloud.common.core.util.CollectionUtils; import com.bsd.pjcloud.hard.api.constant.order.HardOrderStatusEnum; +import com.bsd.pjcloud.hard.api.constant.order.HardOrderTypeEnum; import com.bsd.pjcloud.hard.api.dto.HardManagerDto; import com.bsd.pjcloud.hard.api.dto.order.HardDeptTotalDto; import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto; import com.bsd.pjcloud.hard.api.dto.order.HardOrderSumAndCountDto; import com.bsd.pjcloud.hard.api.entity.HardManagerEntity; import com.bsd.pjcloud.hard.api.utils.HardUtil; -import com.bsd.pjcloud.hard.api.vo.order.HardDeptTotalVo; -import com.bsd.pjcloud.hard.api.vo.order.HardOrderCsVo; -import com.bsd.pjcloud.hard.api.vo.order.HardOrderSbVo; -import com.bsd.pjcloud.hard.api.vo.order.HardOrderSumAndCountVo; +import com.bsd.pjcloud.hard.api.vo.order.*; import com.bsd.pjcloud.hard.mapper.HardManagerMapper; import com.bsd.pjcloud.hard.mapper.order.HardOrderMapper; import com.bsd.pjcloud.hard.service.HardOrderTotalService; @@ -291,4 +289,9 @@ public class HardOrderTotalServiceImpl implements HardOrderTotalService { }); return resultListFuture.join(); } + + @Override + public HardZyCardSyncVo totalYearMonthDay(HardOrderDto dto) { + return hardOrderMapper.totalYearMonthDay(dto); + } } diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/resources/mapper/order/HardOrderMapper.xml b/pjcloud-hardware/pjcloud-hardware-biz/src/main/resources/mapper/order/HardOrderMapper.xml index c45b4df98..df786316d 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/resources/mapper/order/HardOrderMapper.xml +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/resources/mapper/order/HardOrderMapper.xml @@ -189,4 +189,32 @@ group by a.dept_id + \ No newline at end of file diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/zy/foreign/ZyForeignGetRegionIdByTokenDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/zy/foreign/ZyForeignGetRegionIdByTokenDto.java index 2fb97b07c..f777e9113 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/zy/foreign/ZyForeignGetRegionIdByTokenDto.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/zy/foreign/ZyForeignGetRegionIdByTokenDto.java @@ -8,9 +8,6 @@ import lombok.NoArgsConstructor; /** * 获取区域编码 */ -//@Builder -//@AllArgsConstructor -//@NoArgsConstructor @Data public class ZyForeignGetRegionIdByTokenDto { } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/zy/mer/ZyMerSyncDealerInfoDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/zy/mer/ZyMerSyncDealerInfoDto.java index 5343dbe2c..a4e34156e 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/zy/mer/ZyMerSyncDealerInfoDto.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/zy/mer/ZyMerSyncDealerInfoDto.java @@ -14,15 +14,17 @@ import lombok.NoArgsConstructor; @NoArgsConstructor @Data public class ZyMerSyncDealerInfoDto { + + /** + * 所属记账单位编号 + */ + private String EPID; + /** * 商户所在系统的键值 */ private String DealerKeyObj; - /** - * 商户名称 - */ - private String DealerName; /** * 商户是否有效0:禁用 1:有效 @@ -30,9 +32,10 @@ public class ZyMerSyncDealerInfoDto { private Integer IsValid; /** - * 所属记账单位编号 + * 商户名称 */ - private String EPID; + private String DealerName; + /** * 每次推送版本号,格式化为14位字符串,如果是数字不足14位的,前面补0。 @@ -42,5 +45,5 @@ public class ZyMerSyncDealerInfoDto { /** * 商户类型,0食堂餐厅,1超市,2普通商家,3其他;不传默认是食堂餐厅类型 */ - private String DealerType; + private Integer DealerType; } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/zy/self/ZySelfTokenDto.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/zy/self/ZySelfTokenDto.java new file mode 100644 index 000000000..ef92153aa --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/dto/zy/self/ZySelfTokenDto.java @@ -0,0 +1,37 @@ +package com.bsd.pjcloud.thirdparty.dto.zy.self; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ZySelfTokenDto { + /** + * 第三方app用户id + */ + private String appid; + + /** + * 第三方app用户密钥 + */ + private String appSecret; + + /** + * 用户唯一标识 + */ + private String token; + + /** + * 登录时间 + */ + private Long loginTime; + + /** + * 过期时间 + */ + private Long expireTime; +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/ZyBaseEncryptVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/ZyBaseEncryptVo.java new file mode 100644 index 000000000..4250bc0da --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/ZyBaseEncryptVo.java @@ -0,0 +1,17 @@ +package com.bsd.pjcloud.thirdparty.vo.zy; + +import lombok.Data; + +@Data +public class ZyBaseEncryptVo { + // 请求成功 + public static String successCode = "0"; + + private String code; + + private String data; + + public boolean isSuccess() { + return successCode.equals(code); + } +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/ZyBaseVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/ZyBaseVo.java index 6b00ddec4..92b0eaef6 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/ZyBaseVo.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/ZyBaseVo.java @@ -1,14 +1,49 @@ package com.bsd.pjcloud.thirdparty.vo.zy; import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; @Data public class ZyBaseVo { - + // 请求成功 public static String successCode = "0"; - private Integer code; + // 系统繁忙,具体看错误消息msg + public static String errorCode = "-1"; + + // 应用服务错误 + public static String serviceError = "10003"; + + // 无效卡,错误信息可查看msg + public static String invalidCard = "10004"; + + // 记账单位数据不存在,请先同步 + public static String accountBookIsEmpty = "20001"; + + // 请同步最新数据 + public static String syncNewData = "20002"; + + // 缺少签名参数 + public static String signIsEmpty = "30001"; + + // 无效的appId + public static String appIdError = "40001"; + + // 无效的appSecret + public static String appSecretError = "40002"; + + // 数据加密认证失败!sign值验证失败 + public static String signError = "40003"; + + // 无效的access_token + public static String accessTokenError = "40004"; + + public static String defaultErrorMsg = "服务异常,请重试或联系管理员"; + + private String code; private String msg; diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/foreign/ZyForeignGetRegionIdByTokenVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/foreign/ZyForeignGetRegionIdByTokenVo.java index 48ac20905..cb8f15212 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/foreign/ZyForeignGetRegionIdByTokenVo.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/foreign/ZyForeignGetRegionIdByTokenVo.java @@ -12,7 +12,7 @@ public class ZyForeignGetRegionIdByTokenVo extends ZyBaseVo { private VoData data; @Data - static class VoData { + public static class VoData { /** * 区域编码 */ @@ -22,7 +22,7 @@ public class ZyForeignGetRegionIdByTokenVo extends ZyBaseVo { */ private String regionAllName; /** - * 地市简称 + * 地市简称 */ private String regionName; } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/self/ZySelfCorrectVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/self/ZySelfCorrectVo.java index 462a5d028..75877cb8d 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/self/ZySelfCorrectVo.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/self/ZySelfCorrectVo.java @@ -1,13 +1,52 @@ package com.bsd.pjcloud.thirdparty.vo.zy.self; import com.bsd.pjcloud.thirdparty.vo.zy.ZyBaseVo; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; /** * 第三方一卡通系统提供冲正接口 */ @Data +@Builder +@AllArgsConstructor +@NoArgsConstructor public class ZySelfCorrectVo extends ZyBaseVo { + /** + * 帐号 + */ + private String accNum; + /** + * 用户姓名 + */ + private String accName; + + /** + * 人员编号 + */ + private String perCode; + + /** + * 订单流水号,全局唯一,第三方流水号 + */ + private String platformSerialNum; + + /** + * 智慧园区通刷服务平台扣费流水号 + */ + private String serialNum; + + /** + * 消费金额,格式是XX.XX元 + */ + private String amount; + + /** + * 第三方一卡通系统返回正常扣费的时间点 统一为yyyy-MM-dd HH:mm:ss + */ + private String recDate; } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/self/ZySelfGetTokenVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/self/ZySelfGetTokenVo.java index c0eb4310f..bfad755be 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/self/ZySelfGetTokenVo.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/self/ZySelfGetTokenVo.java @@ -1,12 +1,18 @@ package com.bsd.pjcloud.thirdparty.vo.zy.self; import com.bsd.pjcloud.thirdparty.vo.zy.ZyBaseVo; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; /** * 第三方提供获取token */ @Data +@Builder +@AllArgsConstructor +@NoArgsConstructor public class ZySelfGetTokenVo extends ZyBaseVo { private String access_token; diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/self/ZySelfPayVo.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/self/ZySelfPayVo.java index 6900edd3d..456d496af 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/self/ZySelfPayVo.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/vo/zy/self/ZySelfPayVo.java @@ -1,11 +1,52 @@ package com.bsd.pjcloud.thirdparty.vo.zy.self; import com.bsd.pjcloud.thirdparty.vo.zy.ZyBaseVo; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; /** * 第三方一卡通系统提供扣费接口 */ @Data +@Builder +@AllArgsConstructor +@NoArgsConstructor public class ZySelfPayVo extends ZyBaseVo { + + /** + * 帐号 + */ + private String accNum; + + /** + * 用户姓名 + */ + private String accName; + + /** + * 人员编号 + */ + private String perCode; + + /** + * 订单流水号,全局唯一,第三方流水号 + */ + private String platformSerialNum; + + /** + * 智慧园区通刷服务平台扣费流水号 + */ + private String serialNum; + + /** + * 消费金额,格式是XX.XX元 + */ + private String amount; + + /** + * 第三方一卡通系统返回正常扣费的时间点 统一为yyyy-MM-dd HH:mm:ss + */ + private String recDate; } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml b/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml index 478f3da97..66154ccd9 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml @@ -104,6 +104,17 @@ com.bsd pjcloud-common-seata + + commons-codec + commons-codec + 1.15 + + + + io.jsonwebtoken + jjwt + 0.9.1 + diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/ZyConfig.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/ZyConfig.java index 06c702cba..465cc3bef 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/ZyConfig.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/config/ZyConfig.java @@ -22,4 +22,10 @@ public class ZyConfig { private String selfAppSecret; + private Long selfExpiresIn; + + private String selfTokenKey; + + private String selfTokenSecret; + } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/zy/ZySelfController.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/zy/ZySelfController.java new file mode 100644 index 000000000..47e457afd --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/zy/ZySelfController.java @@ -0,0 +1,55 @@ +package com.bsd.pjcloud.thirdparty.controller.zy; + +import com.bsd.pjcloud.thirdparty.dto.zy.self.ZySelfCorrectDto; +import com.bsd.pjcloud.thirdparty.dto.zy.self.ZySelfGetTokenDto; +import com.bsd.pjcloud.thirdparty.dto.zy.self.ZySelfPayDto; +import com.bsd.pjcloud.thirdparty.service.impl.ZySelfService; +import com.bsd.pjcloud.thirdparty.vo.zy.self.ZySelfCorrectVo; +import com.bsd.pjcloud.thirdparty.vo.zy.self.ZySelfGetTokenVo; +import com.bsd.pjcloud.thirdparty.vo.zy.self.ZySelfPayVo; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpHeaders; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.Map; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/third/zy") +@Tag(description = "thirdPartyDept", name = "正元接口对接") +@SecurityRequirement(name = HttpHeaders.AUTHORIZATION) +public class ZySelfController { + + private final ZySelfService zySelfService; + + @GetMapping("/checkSystemStatus") + @Operation(summary = "第三方url健康探测", description = "第三方url健康探测") + public Map checkSystemStatus() { + return zySelfService.checkSystemStatus(); + } + + @GetMapping("/getToken") + @Operation(summary = "第三方提供获取token", description = "第三方提供获取token") + public ZySelfGetTokenVo getToken(ZySelfGetTokenDto params) { + return zySelfService.getToken(params); + } + + + @PostMapping("/correct") + @Operation(summary = "第三方一卡通系统提供冲正接口", description = "第三方一卡通系统提供冲正接口") + public ZySelfCorrectVo correct(@RequestBody ZySelfCorrectDto params, @RequestParam(value = "access_token", required = false) String accessToken) { + return zySelfService.correct(params, accessToken); + } + + @PostMapping("/getToken") + @Operation(summary = "第三方一卡通系统提供扣费接口", description = "第三方一卡通系统提供扣费接口") + public ZySelfPayVo pay(@RequestBody ZySelfPayDto params, @RequestParam(value = "access_token", required = false) String accessToken) { + return zySelfService.pay(params, accessToken); + } + + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ZyDoForeignService.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ZyDoForeignService.java new file mode 100644 index 000000000..2a98a9509 --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ZyDoForeignService.java @@ -0,0 +1,8 @@ +package com.bsd.pjcloud.thirdparty.service; + +public interface ZyDoForeignService { + + // 本地一卡通交易数据同步 + void syncNativeCardTradeInfo(); + +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/ZyForeignService.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/ZyForeignService.java index 88644de6a..bea06710e 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/ZyForeignService.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/ZyForeignService.java @@ -15,6 +15,6 @@ public interface ZyForeignService { /** * 获取区域编码 */ - ZyForeignGetRegionIdByTokenVo getRegionIdByToken(ZyForeignGetRegionIdByTokenDto dto); + ZyForeignGetRegionIdByTokenVo.VoData getRegionIdByToken(); } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/ZyMerService.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/ZyMerService.java index 44f2111f1..dc4cba674 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/ZyMerService.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/ZyMerService.java @@ -6,12 +6,14 @@ import com.bsd.pjcloud.thirdparty.dto.zy.mer.ZyMerSyncDealerInfoDto; import com.bsd.pjcloud.thirdparty.dto.zy.mer.ZyMerSyncEnterpriseInfoDto; import com.bsd.pjcloud.thirdparty.vo.zy.mer.*; +import java.util.List; + public interface ZyMerService { /** * 商户信息同步 */ - ZyMerSyncDealerInfoVo syncDealerInfoApi(ZyMerSyncDealerInfoDto dto); + ZyMerSyncDealerInfoVo syncDealerInfoApi(List dto); /** * 记账单位同步 diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/ZySelfService.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/ZySelfService.java index 013f5c6b7..036ada6e9 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/ZySelfService.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/ZySelfService.java @@ -1,4 +1,33 @@ package com.bsd.pjcloud.thirdparty.service.impl; +import com.bsd.pjcloud.thirdparty.dto.zy.self.ZySelfCorrectDto; +import com.bsd.pjcloud.thirdparty.dto.zy.self.ZySelfGetTokenDto; +import com.bsd.pjcloud.thirdparty.dto.zy.self.ZySelfPayDto; +import com.bsd.pjcloud.thirdparty.vo.zy.self.ZySelfCorrectVo; +import com.bsd.pjcloud.thirdparty.vo.zy.self.ZySelfGetTokenVo; +import com.bsd.pjcloud.thirdparty.vo.zy.self.ZySelfPayVo; + +import java.util.Map; + public interface ZySelfService { + + /** + * 第三方url健康探测 + */ + Map checkSystemStatus(); + + /** + * 第三方提供获取token + */ + ZySelfGetTokenVo getToken(ZySelfGetTokenDto params); + + /** + * 第三方一卡通系统提供冲正接口 + */ + ZySelfCorrectVo correct(ZySelfCorrectDto params, String accessToken); + + /** + * 第三方一卡通系统提供扣费接口 + */ + ZySelfPayVo pay(ZySelfPayDto params, String accessToken); } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZyDoForeignServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZyDoForeignServiceImpl.java new file mode 100644 index 000000000..cc642f6ea --- /dev/null +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZyDoForeignServiceImpl.java @@ -0,0 +1,31 @@ +package com.bsd.pjcloud.thirdparty.service.impl.zy; + +import cn.hutool.core.util.ObjectUtil; +import com.bsd.pjcloud.thirdparty.dto.zy.foreign.ZyForeignSyncNativeCardTradeInfoDto; +import com.bsd.pjcloud.thirdparty.service.ZyDoForeignService; +import com.bsd.pjcloud.thirdparty.vo.zy.foreign.ZyForeignGetRegionIdByTokenVo; +import com.bsd.pjcloud.thirdparty.vo.zy.foreign.ZyForeignSyncNativeCardTradeInfoVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +@Service +@Validated +@Slf4j +@RequiredArgsConstructor +public class ZyDoForeignServiceImpl implements ZyDoForeignService { + + private final ZyForeignServiceImpl zyForeignServiceImpl; + + @Override + public void syncNativeCardTradeInfo() { + ZyForeignGetRegionIdByTokenVo.VoData region = zyForeignServiceImpl.getRegionIdByToken(); + if (ObjectUtil.isEmpty(region)) { + return; + } + ZyForeignSyncNativeCardTradeInfoDto asyncDto = new ZyForeignSyncNativeCardTradeInfoDto(); + asyncDto.setRegionCode(region.getRegionCode()); + ZyForeignSyncNativeCardTradeInfoVo vo = zyForeignServiceImpl.syncNativeCardTradeInfoApi(asyncDto); + } +} diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZyForeignServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZyForeignServiceImpl.java index 70eb8eef5..e8775f4b3 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZyForeignServiceImpl.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZyForeignServiceImpl.java @@ -1,5 +1,6 @@ package com.bsd.pjcloud.thirdparty.service.impl.zy; +import cn.hutool.core.codec.Base64; import cn.hutool.core.util.ObjectUtil; import cn.hutool.http.HttpRequest; import cn.hutool.json.JSONUtil; @@ -9,6 +10,7 @@ import com.bsd.pjcloud.thirdparty.dto.zy.foreign.ZyForeignSyncNativeCardTradeInf import com.bsd.pjcloud.thirdparty.service.impl.ZyForeignService; import com.bsd.pjcloud.thirdparty.utils.zy.api.ZyApi; import com.bsd.pjcloud.thirdparty.utils.zy.api.ZyApiTool; +import com.bsd.pjcloud.thirdparty.vo.zy.ZyBaseEncryptVo; import com.bsd.pjcloud.thirdparty.vo.zy.foreign.ZyForeignGetRegionIdByTokenVo; import com.bsd.pjcloud.thirdparty.vo.zy.foreign.ZyForeignSyncNativeCardTradeInfoVo; import lombok.RequiredArgsConstructor; @@ -64,24 +66,23 @@ public class ZyForeignServiceImpl implements ZyForeignService { * 获取区域编码 */ @Override - public ZyForeignGetRegionIdByTokenVo getRegionIdByToken(ZyForeignGetRegionIdByTokenDto dto) { + public ZyForeignGetRegionIdByTokenVo.VoData getRegionIdByToken() { String url = zyConfig.getBaseUrl() + ZyApi.Foreign.GET_REGION_ID_BY_TOKEN; try { url = String.format(url, zyApiTool.getToken()); - Map encryptionBody = new HashMap<>(); - encryptionBody.put("accClasses", dto); - String body = zyApiTool.getEncryptionDto(encryptionBody); - String res = HttpRequest.post(url) - .body(body) - .execute() - .body(); + String res = HttpRequest.get(url).execute().body(); if (ObjectUtil.isEmpty(res)) { throw new RuntimeException("response is empty"); } - ZyForeignGetRegionIdByTokenVo vo = JSONUtil.toBean(res, ZyForeignGetRegionIdByTokenVo.class); - if (!vo.isSuccess()) { - throw new RuntimeException(String.format("请求错误res|%s|url|%s|body|%s|", res, url, body)); + ZyBaseEncryptVo baseEncryptVo = JSONUtil.toBean(res, ZyBaseEncryptVo.class); + if (ObjectUtil.isEmpty(baseEncryptVo)) { + throw new RuntimeException(String.format("解密错误res|%s|url|%s|res|%s|", res, url, baseEncryptVo)); } + if (!baseEncryptVo.isSuccess()) { + throw new RuntimeException(String.format("请求错误res|%s|url|%s|", res, url)); + } + String json = Base64.decodeStr(baseEncryptVo.getData()); + ZyForeignGetRegionIdByTokenVo.VoData vo = JSONUtil.toBean(json, ZyForeignGetRegionIdByTokenVo.VoData.class); return vo; } catch (Exception e) { log.error("|{}||getRegionIdByToken|意外的错误error|{}|", TAG, e.getMessage()); diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZyMerServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZyMerServiceImpl.java index eb40c5867..6b84d1524 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZyMerServiceImpl.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZyMerServiceImpl.java @@ -1,5 +1,6 @@ package com.bsd.pjcloud.thirdparty.service.impl.zy; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.http.HttpRequest; import cn.hutool.json.JSONUtil; @@ -17,7 +18,9 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; @Service @@ -36,14 +39,23 @@ public class ZyMerServiceImpl implements ZyMerService { * 商户信息同步 */ @Override - public ZyMerSyncDealerInfoVo syncDealerInfoApi(ZyMerSyncDealerInfoDto dto) { + public ZyMerSyncDealerInfoVo syncDealerInfoApi(List dto) { + if (ObjectUtil.isEmpty(dto)) { + return null; + } + List> listMap = new ArrayList<>(); + for (ZyMerSyncDealerInfoDto v : dto) { + Map map = zyApiTool.removeEmptyMap(BeanUtil.beanToMap(v)); + listMap.add(map); + } String url = zyConfig.getBaseUrl() + ZyApi.Mer.SYNC_DEALER_INFO; try { url = String.format(url, zyApiTool.getToken()); Map encryptionBody = new HashMap<>(); - encryptionBody.put("dealers", dto); + encryptionBody.put("dealers", listMap); String body = zyApiTool.getEncryptionDto(encryptionBody); String res = HttpRequest.post(url) + .contentType("application/x-www-form-urlencoded") .body(body) .execute() .body(); diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZySelfServiceImpl.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZySelfServiceImpl.java index 813f39309..fc0b0009f 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZySelfServiceImpl.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/impl/zy/ZySelfServiceImpl.java @@ -1,14 +1,162 @@ package com.bsd.pjcloud.thirdparty.service.impl.zy; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import com.bsd.pjcloud.common.core.constant.CacheConstants; +import com.bsd.pjcloud.thirdparty.config.ZyConfig; +import com.bsd.pjcloud.thirdparty.dto.zy.self.ZySelfCorrectDto; +import com.bsd.pjcloud.thirdparty.dto.zy.self.ZySelfGetTokenDto; +import com.bsd.pjcloud.thirdparty.dto.zy.self.ZySelfPayDto; +import com.bsd.pjcloud.thirdparty.dto.zy.self.ZySelfTokenDto; import com.bsd.pjcloud.thirdparty.service.impl.ZySelfService; +import com.bsd.pjcloud.thirdparty.vo.zy.ZyBaseVo; +import com.bsd.pjcloud.thirdparty.vo.zy.self.ZySelfCorrectVo; +import com.bsd.pjcloud.thirdparty.vo.zy.self.ZySelfGetTokenVo; +import com.bsd.pjcloud.thirdparty.vo.zy.self.ZySelfPayVo; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + @Service @Validated @Slf4j @RequiredArgsConstructor public class ZySelfServiceImpl implements ZySelfService { + + private final String TAG = "第三方需提供的接口api"; + + private final ZyConfig zyConfig; + + private final StringRedisTemplate redisTemplate; + + /** + * 第三方url健康探测 + */ + @Override + public Map checkSystemStatus() { + String systemTime = DateUtil.formatDateTime(new Date()); + Map result = Map.of("systemTime", systemTime); + log.info("|{}|checkSystemStatus res|{}|", TAG, JSONUtil.toJsonStr(result)); + return result; + } + + /** + * 第三方一卡通系统提供冲正接口 + */ + @Override + public ZySelfCorrectVo correct(ZySelfCorrectDto params, String accessToken) { + ZySelfCorrectVo result = new ZySelfCorrectVo(); + result.setCode(ZyBaseVo.errorCode); + boolean isToken = checkIsToken(accessToken); + if (!isToken) { + result.setCode(ZyBaseVo.accessTokenError); + result.setMsg("无效的access_token"); + return result; + } + + return null; + } + + /** + * 第三方一卡通系统提供扣费接口 + */ + @Override + public ZySelfPayVo pay(ZySelfPayDto params, String accessToken) { + ZySelfCorrectVo result = new ZySelfCorrectVo(); + result.setCode(ZyBaseVo.errorCode); + boolean isToken = checkIsToken(accessToken); + if (!isToken) { + result.setCode(ZyBaseVo.accessTokenError); + result.setMsg("无效的access_token"); + } + + return null; + } + + /** + * 第三方提供获取token + */ + @Override + public ZySelfGetTokenVo getToken(ZySelfGetTokenDto params) { + ZySelfGetTokenVo result = new ZySelfGetTokenVo(); + result.setCode(ZyBaseVo.errorCode); + if (ObjectUtil.isEmpty(params.getAppid()) || ObjectUtil.equals(params.getAppid(), zyConfig.getSelfAppId())) { + result.setMsg("appid 无效"); + return result; + } + if (ObjectUtil.isEmpty(params.getAppsecret()) || ObjectUtil.equals(params.getAppsecret(), zyConfig.getSelfAppSecret())) { + result.setMsg("appSecret 无效"); + return result; + } + String redisKey = CacheConstants.THIRDPARTY_ZY_SELF_TOKEN; + redisTemplate.opsForValue().getAndDelete(redisKey); + try { + // 生成token + String token = generateToken(params); + result.setCode(ZyBaseVo.successCode); + result.setAccess_token(token); + result.setExpires_in(zyConfig.getSelfExpiresIn().toString()); + return result; + } catch (Exception e) { + log.error("|{}|getToken意外的错误dto|{}|error|{}|stack|{}|", TAG, JSONUtil.toJsonStr(params), e.getMessage(), e.getStackTrace()); + result.setMsg(ZyBaseVo.defaultErrorMsg); + return result; + } + } + + private boolean checkIsToken(String string) { + if (ObjectUtil.isEmpty(string)) { + log.info("|{}|checkIsToken校验错误,未传入token|{}|", TAG, string); + return false; + } + Claims claims = Jwts.parser() + .setSigningKey(zyConfig.getSelfAppSecret()) + .parseClaimsJws(string) + .getBody(); + String token = (String) claims.get(zyConfig.getSelfTokenKey()); + String redisKey = CacheConstants.THIRDPARTY_ZY_SELF_TOKEN + token; + String json = redisTemplate.opsForValue().get(redisKey); + if (ObjectUtil.isEmpty(json)) { + log.info("|{}|checkIsToken校验错误token|{}|", TAG, string); + return false; + } + log.info("|{}|checkIsToken校验成功info|{}|", TAG, json); + return true; + } + + // 生成token + private String generateToken(ZySelfGetTokenDto dto) { + ZySelfTokenDto selfTokenDto = new ZySelfTokenDto(); + String token = IdUtil.fastUUID(); + Map claims = new HashMap<>(); + claims.put(zyConfig.getSelfTokenKey(), token); + // 刷新token + selfTokenDto.setToken(token); + selfTokenDto.setAppid(dto.getAppid()); + selfTokenDto.setAppSecret(dto.getAppsecret()); + refreshToken(selfTokenDto); + return Jwts.builder() + .setClaims(claims) + .signWith(SignatureAlgorithm.HS512, zyConfig.getSelfTokenSecret()).compact(); + } + + /// 刷新token + public void refreshToken(ZySelfTokenDto dto) { + dto.setLoginTime(System.currentTimeMillis()); + dto.setExpireTime(dto.getLoginTime() + zyConfig.getSelfExpiresIn() + 100); + String redisKey = CacheConstants.THIRDPARTY_ZY_SELF_TOKEN + dto.getToken(); + redisTemplate.opsForValue().set(redisKey, JSONUtil.toJsonStr(dto), zyConfig.getSelfExpiresIn(), TimeUnit.MINUTES); + } } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/utils/zy/api/ZyApiTool.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/utils/zy/api/ZyApiTool.java index 8d2cdd8d1..38537786b 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/utils/zy/api/ZyApiTool.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/utils/zy/api/ZyApiTool.java @@ -1,23 +1,27 @@ package com.bsd.pjcloud.thirdparty.utils.zy.api; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.codec.Base64; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.URLUtil; import cn.hutool.http.HttpRequest; import cn.hutool.json.JSONUtil; import com.bsd.pjcloud.common.core.constant.CacheConstants; import com.bsd.pjcloud.thirdparty.config.ZyConfig; import com.bsd.pjcloud.thirdparty.vo.zy.mer.ZyMerGetTokenVo; +import io.undertow.security.idm.DigestAlgorithm; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import org.springframework.validation.annotation.Validated; +import org.apache.commons.codec.digest.DigestUtils; -import java.nio.charset.StandardCharsets; -import java.util.Base64; import java.util.HashMap; import java.util.Map; - -import static org.apache.commons.codec.digest.DigestUtils.md5Hex; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.TimeUnit; @Component @Validated @@ -25,13 +29,13 @@ import static org.apache.commons.codec.digest.DigestUtils.md5Hex; @RequiredArgsConstructor public class ZyApiTool { - private final String TAG = "正元请求工具类"; + static private final String TAG = "正元请求工具类"; private final ZyConfig zyConfig; private final StringRedisTemplate redisTemplate; - public ZyMerGetTokenVo getTokenApi() { + public ZyMerGetTokenVo getTokenApi() throws Exception { String url = zyConfig.getBaseUrl() + ZyApi.Mer.GET_TOKEN; url = String.format(url, zyConfig.getAppId(), zyConfig.getAppSecret()); try { @@ -43,12 +47,12 @@ public class ZyApiTool { throw new RuntimeException("response is empty"); } ZyMerGetTokenVo vo = JSONUtil.toBean(res, ZyMerGetTokenVo.class); - if (!vo.isSuccess()) { + if (ObjectUtil.isEmpty(vo) || !ObjectUtil.isAllNotEmpty(vo.getAccess_token(), vo.getExpires_in())) { throw new RuntimeException(String.format("请求错误res|%s|url|%s|", res, url)); } return vo; } catch (Exception e) { - log.error("|{}||getTokenApi|意外的错误error|{}|", TAG, e.getMessage()); + log.error("|{}||getTokenApi|意外的错误error|{}|stack:|{}|", TAG, e.getMessage(), e.getStackTrace()); } return null; } @@ -61,7 +65,16 @@ public class ZyApiTool { ZyMerGetTokenVo vo = getTokenApi(); if (ObjectUtil.isNotEmpty(vo)) { String accessToken = vo.getAccess_token(); + String expiresIn = vo.getExpires_in(); redisTemplate.opsForValue().set(redisKey, accessToken); + try { + long expiresInNum = Long.parseLong(expiresIn); + if (ObjectUtil.isNotEmpty(expiresInNum) && expiresInNum > 100) { + redisTemplate.expire(redisKey, expiresInNum - 100, TimeUnit.SECONDS); + } + } catch (Exception e) { + log.error("|{}|意外的错误error|{}|stack|{}|", TAG, e.getMessage(), e.getStackTrace()); + } return accessToken; } } @@ -72,15 +85,58 @@ public class ZyApiTool { return null; } - public String getEncryptionDto(T params) { - String json = JSONUtil.toJsonStr(params); - String encodedData = Base64.getEncoder().encodeToString(json.getBytes(StandardCharsets.UTF_8)); - String stringToSign = String.format("data=%s&key=%s", json, zyConfig.getAppId()); - String sign = md5Hex(stringToSign); + public String getEncryptionDto(Map params) { Map body = new HashMap<>(); - body.put("data", encodedData); - body.put("sign", sign); + body.put("data", params); + prePost(body); return JSONUtil.toJsonStr(body); } + public Map removeEmptyMap(Map params) { + for (Map.Entry entry : params.entrySet()) { + Object value = entry.getValue(); + if (value == null) { + params.remove(entry.getKey()); + } + } + return params; + } + + private void prePost(Map params) { + for (Map.Entry entry : params.entrySet()) { + Object value = entry.getValue(); + if (value instanceof String) { + entry.setValue(URLUtil.encode((String) value)); + } else { + String json = JSONUtil.toJsonStr(value); + entry.setValue(json); + } + } + String sign = generateSign(params); + for (Map.Entry entry : params.entrySet()) { + Object value = entry.getValue(); + if (value instanceof String) { + entry.setValue(Base64.encode((String) value)); + } else { + entry.setValue(Base64.encode(value.toString())); + } + } + params.put("sign", sign); + } + + private String generateSign(Map params) { + // 将参数以参数名的字典升序排序 + Map sortParams = new TreeMap(params); + Set> entrys = sortParams.entrySet(); + StringBuilder baseString = new StringBuilder(); + for (Map.Entry entry : entrys) { + baseString.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); + } + baseString.append("key=").append(zyConfig.getAppId()); + String signStr = baseString.toString(); + String digestHex = DigestUtils.md5Hex(signStr); + log.info("|{}|加密前的参数为|{}|加密后的参数为|{}|", TAG, signStr, digestHex); + return digestHex; + } + } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/application.yml b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/application.yml index d47c081c7..53d9fde2b 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/application.yml +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/resources/application.yml @@ -45,8 +45,15 @@ oauth2: # https://gwyc.zj.gov.cn/API/%E7%9C%81%E5%B9%B3%E5%8F%B0API%E5%AF%B9%E6%8E%A5%E6%8E%A5%E5%8F%A3.html zy: base-url: http://60.191.37.212:18079 - app-id: 03D9608D1735D424F984733BA71321C6 - app-secret: 65497A86DB1401B252FEA6DE0A080766 + app-id: 689C8D6F5059A6F85B8BE45A49001ACB + app-secret: BD21DA0DEB8F0FC43246B0BD2FCAE6FF + self-base-url: http://60.191.37.212:18079 - self-app-id: 03D9608D1735D424F984733BA71321C6 - self-app-secret: 03D9608D1735D424F984733BA71321C6 \ No newline at end of file + self-app-id: xA5jF2vX4zO5mQ8tR9yE7rC7iI0fK0kI + self-app-secret: kE3hH5gF7zN0nH1yI5yX3vP0oP1hU0jE + # 失效时间单位秒 + self-expires-in: 7200 + # token key + self_token_key: zy_token + # token + self_token_secret: eV3dT0oD7iX8rK4eC3jS6fU8cU5cS6mJ \ No newline at end of file diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/test/java/com/bsd/pjcloud/admin/ZyTest.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/test/java/com/bsd/pjcloud/admin/ZyTest.java index 6197eb9ee..7a815b294 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/test/java/com/bsd/pjcloud/admin/ZyTest.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/test/java/com/bsd/pjcloud/admin/ZyTest.java @@ -1,5 +1,6 @@ package com.bsd.pjcloud.admin; +import cn.hutool.core.date.DateUtil; import cn.hutool.json.JSONUtil; import com.bsd.pjcloud.thirdparty.ThirdPartyApp; import com.bsd.pjcloud.thirdparty.dto.zy.foreign.ZyForeignGetRegionIdByTokenDto; @@ -21,13 +22,16 @@ import com.bsd.pjcloud.thirdparty.vo.zy.mer.*; import com.bsd.pjcloud.thirdparty.vo.zy.stride.ZyStrideAuthenticationVo; import com.bsd.pjcloud.thirdparty.vo.zy.stride.ZyStrideConsumptionVo; import com.bsd.pjcloud.thirdparty.vo.zy.stride.ZyStrideCorrectVo; +import io.undertow.security.idm.DigestAlgorithm; import jakarta.annotation.Resource; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.Base64; import java.util.HashMap; +import java.util.List; import java.util.Map; @SpringBootTest(classes = ThirdPartyApp.class) @@ -49,9 +53,9 @@ public class ZyTest { * 获取token */ @Test - public void merGetTokenApi() { - ZyMerGetTokenVo vo = zyApiTool.getTokenApi(); - System.out.println(vo); + public void merGetTokenApi() throws Exception { + String token = zyApiTool.getToken(); + System.out.println(token); } /** @@ -59,15 +63,17 @@ public class ZyTest { */ @Test public void merSyncDealerInfo() { + String currentIndex = String.valueOf(DateUtil.current()); ZyMerSyncDealerInfoDto dto = ZyMerSyncDealerInfoDto .builder() - .DealerKeyObj("123") - .DealerName("食堂") + .DealerKeyObj(currentIndex) + .DealerName("食堂" + currentIndex) .IsValid(1) - .EPID("1") + .EPID("EPID" + currentIndex) .FixId("20190920100101") .build(); - ZyMerSyncDealerInfoVo vo = zyMerService.syncDealerInfoApi(dto); + List list = List.of(dto); + ZyMerSyncDealerInfoVo vo = zyMerService.syncDealerInfoApi(list); System.out.println(vo); } @@ -121,8 +127,7 @@ public class ZyTest { */ @Test public void foreignGetRegionIdByToken() { - ZyForeignGetRegionIdByTokenDto dto = new ZyForeignGetRegionIdByTokenDto(); - ZyForeignGetRegionIdByTokenVo vo = zyForeignService.getRegionIdByToken(dto); + ZyForeignGetRegionIdByTokenVo.VoData vo = zyForeignService.getRegionIdByToken(); System.out.println(vo); } @@ -165,57 +170,26 @@ public class ZyTest { /************************** end stride end **************************/ @Test - public void encryption() { - try { + public void encryption() throws Exception { + // 第一步:组装业务数据 + String data = "{\"dealers\":[{\"EPID\": \"1\",\"DealerKeyObj\":\"123\",\"IsValid\":1,\"DealerName\":\"食堂\",\"FixId\":\"20190920100101\"}]}"; - // 1. 构建业务数据 - Map dealer = new HashMap<>(); - dealer.put("EPID", "1"); - dealer.put("DealerKeyObj", "123"); - dealer.put("IsValid", 1); - dealer.put("DealerName", "食堂"); - dealer.put("FixId", "20190920100101"); + // 第二步:进行 Base64 编码 + String encodedData = Base64.getEncoder().encodeToString(data.getBytes(StandardCharsets.UTF_8)); - Map data = new HashMap<>(); - data.put("dealers", new Object[]{dealer}); - - // 2. 生成 data 参数(Base64 编码) - String jsonData = JSONUtil.toJsonStr(data); - String base64Data = Base64.getEncoder().encodeToString(jsonData.getBytes("UTF-8")); - - // 3. 生成签名 - String signStr = String.format("data=%s&key=%s", jsonData, "03D9608D1735D424F984733BA71321C6"); - String sign = md5(signStr).toUpperCase(); - - // 4. 构建请求参数 - Map params = new HashMap<>(); - params.put("data", base64Data); - params.put("sign", sign); - System.out.println(params); - } catch (Exception e) { - e.printStackTrace(); - } + // 输出结果 + System.out.println("Base64 Encoded Data: " + encodedData); } - // MD5 加密方法 - private static String md5(String input) { - try { - MessageDigest md = MessageDigest.getInstance("MD5"); - byte[] messageDigest = md.digest(input.getBytes()); - StringBuilder hexString = new StringBuilder(); - for (byte b : messageDigest) { - String hex = Integer.toHexString(0xFF & b); - if (hex.length() == 1) { - hexString.append('0'); - } - hexString.append(hex); - } - - return hexString.toString(); - } catch (Exception e) { - throw new RuntimeException(e); + private static String md5(String input) throws Exception { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8)); + StringBuilder sb = new StringBuilder(); + for (byte b : messageDigest) { + sb.append(String.format("%02x", b)); } + return sb.toString(); } }