Commit fcb47335 authored by 吴琼's avatar 吴琼

处理冲突

parents 0245e681 fb5a0b6b
...@@ -52,6 +52,22 @@ ...@@ -52,6 +52,22 @@
<encoding>${project.build.sourceEncoding}</encoding> <encoding>${project.build.sourceEncoding}</encoding>
</configuration> </configuration>
</plugin> </plugin>
<!-- <plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>-->
</plugins> </plugins>
</build> </build>
...@@ -253,6 +269,7 @@ ...@@ -253,6 +269,7 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.itextpdf</groupId> <groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId> <artifactId>itextpdf</artifactId>
...@@ -277,8 +294,21 @@ ...@@ -277,8 +294,21 @@
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId> <artifactId>spring-test</artifactId>
</dependency> </dependency>
<!--fastdfs-->
<!--<dependency> <!--<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>4.2.1</version>
<scope>provided</scope>
</dependency>-->
<dependency>
<groupId>com.github.tobato</groupId> <groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId> <artifactId>fastdfs-client</artifactId>
<version>1.25.2-RELEASE</version> <version>1.25.2-RELEASE</version>
...@@ -296,11 +326,18 @@ ...@@ -296,11 +326,18 @@
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency>--> </dependency>
<!-- <dependency> <!-- <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId> <artifactId>spring-test</artifactId>
</dependency>--> </dependency>-->
<!-- sftp -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
</dependencies> </dependencies>
</project> </project>
package cn.quantgroup.customer; package cn.quantgroup.customer;
import com.github.tobato.fastdfs.FdfsClientConfig;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.support.RegistrationPolicy;
@Import(FdfsClientConfig.class)
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
@Configuration @Configuration
@ServletComponentScan @ServletComponentScan
@EnableAspectJAutoProxy @EnableAspectJAutoProxy
......
...@@ -40,13 +40,16 @@ public class CrosFilter implements Filter { ...@@ -40,13 +40,16 @@ public class CrosFilter implements Filter {
String allowedOrigin = "*"; String allowedOrigin = "*";
response.setHeader("Access-Control-Allow-Origin", allowedOrigin); response.setHeader("Access-Control-Allow-Origin", allowedOrigin);
response.setHeader("Access-Control-Allow-Methods", "POST, GET"); response.setHeader("Access-Control-Allow-Methods", "POST, GET");
String allowedHeaders = "Origin, No-Cache, x-auth-token, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type,Authorization"; String allowedHeaders = "Origin, No-Cache, x-auth-token, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type,Authorization" +
"Accept,Access-Token,Account,Account-Name,Referer,sec-ch-ua,sec-ch-ua-mobile,sec-ch-ua-platform,User-Agent";
response.setHeader("Access-Control-Allow-Headers", allowedHeaders); response.setHeader("Access-Control-Allow-Headers", allowedHeaders);
response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Max-Age", "3600");
if (DISALLOWED_METHOD.contains(request.getMethod())) { if (DISALLOWED_METHOD.contains(request.getMethod())) {
return; return;
} }
filterChain.doFilter(servletRequest, servletResponse); filterChain.doFilter(servletRequest, servletResponse);
} }
@Override @Override
......
...@@ -26,7 +26,7 @@ import java.util.Objects; ...@@ -26,7 +26,7 @@ import java.util.Objects;
* @Desc 鉴权过滤器 * @Desc 鉴权过滤器
* @Update * @Update
*/ */
@WebFilter(filterName = "operatePermitFilter",urlPatterns = {"/operate/sys/*","/repay/earlySettleOperate"}) @WebFilter(filterName = "operatePermitFilter",urlPatterns = {"/operate/sys/*","/repay/earlySettleOperate","/vcc/*"})
@Slf4j @Slf4j
public class ValidOperatePermitFilter implements Filter { public class ValidOperatePermitFilter implements Filter {
@Autowired @Autowired
......
package cn.quantgroup.customer.entity;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
@Entity
@Table(name = "offline_repay_operate_record")
@ToString
@Builder
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@DynamicUpdate
@DynamicInsert
public class OfflineRepayOperateRecord implements Serializable {
private static final long serialVersionUID = -9206318459421433518L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "serial_no")
private String serialNo;
@Column(name = "operate_account")
private String operateAccount;
@Column(name = "operate_name")
private String operateName;
@Column(name = "operate_content")
private String operateContent;
@Column(name = "operate_time")
private Date operateTime;
@Column(name = "remark")
private String remark;
@Column(name = "create_time")
private Date createTime;
@Column(name = "update_time")
private Date updateTime;
}
package cn.quantgroup.customer.entity;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import javax.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
@Entity
@Table(name = "offline_repay_submit_record")
@ToString
@Builder
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@DynamicInsert
@DynamicUpdate
public class OfflineRepaySubmitRecord implements Serializable {
private static final long serialVersionUID = 2930019435843122345L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "serial_no")
private String serialNo;
@Column(name = "unique_id")
private String uniqueId;
@Column(name = "bills")
private String bills;
@Column(name = "curr_term")
private Integer currTerm;
@Column(name = "amount")
private BigDecimal amount;
@Column(name = "actual_amount")
private BigDecimal actualAmount;
@Column(name = "actual_date")
private Date actualDate;
@Column(name = "trans_no")
private String transNo;
@Column(name = "receive_account")
private String receiveAccount;
@Column(name = "receive_account_name")
private String receiveAccountName;
@Column(name = "credentials_address")
private String credentialsAddress;
@Column(name = "mark")
private String mark;
@Column(name = "repay_type")
private Integer repayType;
@Column(name = "user_id")
private Integer userId;
@Column(name = "name")
private String name;
@Column(name = "phone")
private String phone;
@Column(name = "id_no")
private String idNo;
@Column(name = "repay_status")
private String repayStatus;
@Column(name = "approval_status")
private Integer approvalStatus;
@Column(name = "create_time")
private Date createTime;
@Column(name = "update_time")
private Date updateTime;
}
package cn.quantgroup.customer.enums;
public enum ApprovalStatus {
APPROVAL_PROCESSING(0,"审批中"),
APPROVAL_PASS(1,"审批通过"),
APPROVAL_REFUSE(2,"审批拒绝");
private Integer code;
private String desc;
ApprovalStatus(Integer code,String desc){
this.code = code;
this.desc = desc;
}
public static String getDescByValue(Integer value){
for (ApprovalStatus approvalStatus:ApprovalStatus.values()){
if (approvalStatus.code.equals(value)){
return approvalStatus.desc;
}
}
return "";
}
}
package cn.quantgroup.customer.enums;
public enum VccRepayStatusEnum {
/**
* 正常状态,主要包括:还款计划未出账、额度状态正常
*/
Normal("正常"),
/**
* 还款状态,主要包括:账单待还款、还款计划待还款
* 韩伟:待还款,生成账单后
*/
Repay("还款"),
/**
* 逾期状态,主要包括:账单逾期、还款计划逾期
*/
Overdue("逾期"),
/**
* 完结状态,主要包括:账单还清、还款计划还清、分期交易还清
*/
Finish("完结"),
/**
* 完成状态, 主要包括:交易完成
*/
Complete("完成");
private String desc;
private VccRepayStatusEnum(String desc){
this.desc = desc;
}
public static String getDescByValue(String value){
for (VccRepayStatusEnum statusEnum:VccRepayStatusEnum.values()){
if (statusEnum.toString().equals(value)){
return statusEnum.desc;
}
}
return "";
}
}
package cn.quantgroup.customer.model.ftp;
import lombok.Data;
/**
* @author yexiong.wang
* @date 2022/02/27
*/
@Data
public class FileInfo {
private String fileName;
private byte[] fileBytes;
private String filePath;
public FileInfo(String fileName, byte[] fileBytes, String filePath) {
this.fileName = fileName;
this.fileBytes = fileBytes;
this.filePath = filePath;
}
}
package cn.quantgroup.customer.model.ftp;
import lombok.Builder;
import lombok.Data;
/**
* @author yexiong.wang
* @date 2022/02/27
*/
@Data
@Builder
public class ServerInfo {
private String username;
private String password;
private String host;
private String directory;
private int port;
}
package cn.quantgroup.customer.repo;
import cn.quantgroup.customer.entity.OfflineRepayOperateRecord;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface OfflineRepayOperateRecordRepo extends JpaRepository<OfflineRepayOperateRecord,Long> {
List<OfflineRepayOperateRecord> findBySerialNoEquals(String serailNo);
}
package cn.quantgroup.customer.repo;
import cn.quantgroup.customer.entity.OfflineRepaySubmitRecord;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import java.util.List;
public interface OfflineRepaySubmitRecordRepo extends JpaRepository<OfflineRepaySubmitRecord,Long>, QueryDslPredicateExecutor<OfflineRepaySubmitRecord> {
OfflineRepaySubmitRecord findBySerialNoEquals(String serialNo);
OfflineRepaySubmitRecord findFirstByUniqueIdEquals(String uniqueId);
OfflineRepaySubmitRecord findFirstByUniqueIdEqualsAndApprovalStatusNot(String uniqueId,Integer approvalStatus);
List<OfflineRepaySubmitRecord> findByUserIdEqualsAndRepayTypeEquals(Integer userId,Integer repayType);
List<OfflineRepaySubmitRecord> findByUserIdEqualsAndRepayTypeEqualsAndApprovalStatusNot(Integer userId,Integer repayType,Integer approvalStatus);
OfflineRepaySubmitRecord findBySerialNoEqualsAndApprovalStatusEquals(String serialNo,Integer approvalStatus);
}
package cn.quantgroup.customer.rest;
import cn.quantgroup.customer.aop.OperateLog;
import cn.quantgroup.customer.rest.param.vcc.OfflineRepaySubmitParam;
import cn.quantgroup.customer.rest.param.vcc.UserPreRepayInfoQuery;
import cn.quantgroup.customer.rest.vo.JsonResult;
import cn.quantgroup.customer.service.IVccService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.Map;
import java.util.Objects;
@Slf4j
@RestController
@RequestMapping("/vcc")
public class VccRest {
@Autowired
private IVccService vccService;
/**
* 查询用户的待还款信息
* @param query
* @return
*/
@PostMapping("/offline_pre_repay/query_page")
@OperateLog(moduleName = "查询用户的待还款信息")
public JsonResult queryPage(@RequestBody @Valid UserPreRepayInfoQuery query, BindingResult bindingResult){
if (bindingResult.hasErrors()){
return JsonResult.buildErrorStateResult(bindingResult.getFieldError().getField() + ":" + bindingResult.getFieldError().getDefaultMessage());
}
log.info("queryPage | 开始用户待还款查询,param={}",query);
if (StringUtils.isBlank(query.getBillId()) && StringUtils.isBlank(query.getPhone())
&& StringUtils.isBlank(query.getUserId()) && StringUtils.isBlank(query.getOrderNo())){
log.error("queryPage | 请求参数userId,phone,billId,orderNo不能同时为空");
return JsonResult.buildErrorStateResult("请求参数userId,phone,billId,orderNo不能同时为空");
}
try {
JsonResult jsonResult = vccService.queryPage(query);
log.info("queryPage | 结束用户待还款查询,param={}",query);
return jsonResult;
} catch (Exception e){
log.error("queryPage | 用户待还款查询发生异常",e);
return JsonResult.buildErrorStateResult("用户待还款查询发生异常:"+ e.getMessage());
}
}
/**
* 查询分期账单的详情
* @param uniqueId
* @param repayType
* @return
*/
@GetMapping("/pre_repay_cal/detail")
@OperateLog(moduleName = "查询分期账单的详情")
public JsonResult repayPlanDetail(@NotNull String uniqueId,@NotNull Integer repayType){
log.info("repayPlanDetail | 查询用户分期的详情及试算详情,uniqueId={},repayType={}",uniqueId,repayType);
try {
JsonResult jsonResult = vccService.queryRepayCalDetail(uniqueId,repayType);
log.info("repayPlanDetail | 结束查询用户分期的详情及试算详情,uniqueId={},repayType={}",uniqueId,repayType);
return jsonResult;
} catch (Exception e){
log.error("repayPlanDetail | 查询用户分期的详情及试算详情发生异常",e);
return JsonResult.buildErrorStateResult("查询用户分期的详情及试算详情发生异常:"+e.getMessage());
}
}
/**
* 保存线下还款的申请记录
* @param request
* @param param
* @return
*/
@PostMapping("/offline_repay/save_submit")
@OperateLog(moduleName = "保存线下还款的申请记录")
public JsonResult saveSubmit(HttpServletRequest request, @RequestBody@Valid OfflineRepaySubmitParam param,BindingResult bindingResult){
if (bindingResult.hasErrors()){
return JsonResult.buildErrorStateResult(bindingResult.getFieldError().getField() + ":" + bindingResult.getFieldError().getDefaultMessage());
}
if (param.getRepayType() == 1){
if (CollectionUtils.isEmpty(param.getList())){
return JsonResult.buildErrorStateResult("还款月还账单时,账单不能为空");
}
}else {
if (StringUtils.isBlank(param.getUniqueId())){
return JsonResult.buildErrorStateResult("提前结清时单号不能为空");
}
if (Objects.isNull(param.getCurrTerm())){
return JsonResult.buildErrorStateResult("提前结清开始期数不能为空");
}
}
log.info("saveSubmit | 开始保存线下还款的申请记录,param={}",param);
try {
String token = request.getHeader("x-auth-token");
vccService.saveSubmitRecord(param,token);
log.info("saveSubmit | 保存线下还款的申请记录成功,param={}",param);
return JsonResult.buildSuccessResult("请求成功",null);
} catch (Exception e){
log.error("saveSubmit | 保存线下还款提交申请时发生异常",e);
return JsonResult.buildErrorStateResult("保存线下还款提交申请时发生异常:"+e.getMessage());
}
}
/**
* 审批回显提交的线下还款申请记录
* @param serialNo
* @return
*/
@GetMapping("/offline_repay/approval")
@OperateLog(moduleName = "审批回显提交的线下还款申请记录")
public JsonResult approval(@NotNull String serialNo){
log.info("approval | 开始点击审批按钮查询信息,serialNo={}",serialNo);
try {
OfflineRepaySubmitParam param = vccService.approvalQuery(serialNo);
log.info("approval | 点击审批按钮查询信息成功,serialNo={}",serialNo);
return JsonResult.buildSuccessResult("请求成功",param);
} catch (Exception e){
log.error("approval | 点击审批按钮查询信息时发生异常",e);
return JsonResult.buildErrorStateResult("点击审批按钮查询信息时发生异常:",e.getMessage());
}
}
/**
* 查看审批流水记录
* @param serialNo
* @return
*/
@GetMapping("/approval/detail")
@OperateLog(moduleName = "查看审批流水记录")
public JsonResult queryApprovalRecord(@NotNull String serialNo){
log.info("queryApprovalRecord | 开始查看审批流水记录,serialNo={}",serialNo);
try {
JsonResult jsonResult = vccService.queryApprovalRecord(serialNo);
log.info("queryApprovalRecord | 查看审批流水记录成功,serialNo={}",serialNo);
return jsonResult;
} catch (Exception e){
log.error("queryApprovalRecord | 查询审批流水时发生异常",e);
return JsonResult.buildErrorStateResult("查询审批流水时发生异常:"+e.getMessage());
}
}
/**
* 审批结果:通过/拒绝
* @param request
* @param serialNo
* @param remark
* @param status
* @return
*/
@GetMapping("/approval/result")
@OperateLog(moduleName = "审批结果:通过/拒绝")
public JsonResult approvalResult(HttpServletRequest request,@NotNull String serialNo,String remark,@NotNull Integer status){
log.info("approvalResult | 开始提交审批结果,serialNo={},remark={},status={}",serialNo,remark,status);
try {
String token = request.getHeader("x-auth-token");
vccService.approvalResult(serialNo,remark,status,token);
log.info("approvalResult | 提交审批结果成功,serialNo={},remark={},status={}",serialNo,remark,status);
return JsonResult.buildSuccessResult("请求成功",null);
}catch (Exception e){
log.error("approvalResult | 通过/拒绝审批时发生异常",e);
return JsonResult.buildErrorStateResult("通过/拒绝审批时发生异常:"+ e.getMessage());
}
}
/**
* 上传打款凭证
* @param file
* @return
*/
@PostMapping("/offline_repay_file/upload")
@OperateLog(moduleName = "上传打款凭证")
public JsonResult fileUpload (MultipartFile file){
log.info("fileUpload | 开始上传打款凭证");
try {
Map<String, String> map = vccService.fileUpload(file);
log.info("fileUpload | 上传打款凭证成功map={}",map);
return JsonResult.buildSuccessResult("请求成功",map);
}catch (Exception e){
log.error("fileUpload | 文件上传时发生异常",e);
return JsonResult.buildErrorStateResult("文件上传时发生异常:"+e.getMessage());
}
}
/**
* 查询线下还款的申请记录
* @param query
* @return
*/
@PostMapping("/approval/query_applly_record")
@OperateLog(moduleName = "查询线下还款的申请记录")
public JsonResult queryApplyRecord(@RequestBody@Valid UserPreRepayInfoQuery query,BindingResult bindingResult){
if (bindingResult.hasErrors()){
return JsonResult.buildErrorStateResult(bindingResult.getFieldError().getField() + ":" + bindingResult.getFieldError().getDefaultMessage());
}
if (StringUtils.isBlank(query.getBillId()) && StringUtils.isBlank(query.getPhone())
&& StringUtils.isBlank(query.getUserId()) && StringUtils.isBlank(query.getOrderNo())){
log.error("queryPage | 请求参数userId,phone,billId,orderNo不能同时为空");
return JsonResult.buildErrorStateResult("请求参数userId,phone,billId,orderNo不能同时为空");
}
log.info("queryApplyRecord | 开始查看线下还款的申请记录,param={}",query);
try {
JsonResult jsonResult = vccService.queryApplyRecord(query);
log.info("queryApplyRecord | 查看线下还款的申请记录成功,param={}",query);
return jsonResult;
}catch (Exception e){
log.error("queryApplyRecord | 查询线下还款申请记录时发生异常",e);
return JsonResult.buildErrorStateResult("查询线下还款申请记录时发生异常:"+e.getMessage());
}
}
}
package cn.quantgroup.customer.rest.param.vcc;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Objects;
@Data
public class ApplyBill {
private Long billId;
private BigDecimal amount;
@Override
public boolean equals(Object o){
if (o == null){
return false;
}
if (o instanceof ApplyBill){
ApplyBill applyBill = (ApplyBill) o;
return Objects.equals(applyBill.billId, this.billId);
}
return super.equals(o);
}
}
package cn.quantgroup.customer.rest.param.vcc;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
@Data
public class OfflineRepaySubmitParam {
private String uniqueId;
private List<ApplyBill> list;
private Integer currTerm;
@NotNull
private BigDecimal amount;
@NotNull
private BigDecimal actualAmount;
@NotNull
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date actualDate;
@NotBlank
private String transNo;
@NotBlank
private String receiveAccount;
@NotBlank
private String receiveAccountName;
@NotEmpty
private List<String> credentialsAddress;
private String mark;
@NotNull
private Integer repayType;
@NotBlank
private String name;
@NotBlank
private String phone;
@NotBlank
private String idNo;
@NotBlank
private String repayStatus;
@NotNull
private Integer userId;
}
package cn.quantgroup.customer.rest.param.vcc;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
public class UserPreRepayInfoQuery {
private String userId;
private String phone;
private String billId;
private String orderNo;
private Integer approvalStatus;
/**
* 1.月还账单 2.账单分期 3.订单分期
*/
@NotNull
private Integer repayType;
//当前页数
@NotNull
private Integer pageIndex;
//默认每页条数
@NotNull
private Integer pageSize;
}
package cn.quantgroup.customer.rest.vo.vcc;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class QueryPreOfflineRepayVo {
private String uniqueId;
private String name;
private String phone;
private String idNo;
private String installTime;
private Integer installTerm;
private Integer currTerm;
private BigDecimal currBall;
private BigDecimal settleAmount;
private String repayStatus;
private String repayStatusName;
private String billTime;
private String repayTime;
private String serialNo;
private Integer approvalStatus;
private Integer userId;
}
package cn.quantgroup.customer.rest.vo.vcc;
import cn.quantgroup.customer.entity.OfflineRepaySubmitRecord;
import lombok.Data;
@Data
public class QuerySubmitRecordVo extends OfflineRepaySubmitRecord {
private static final long serialVersionUID = -1359026440976090642L;
private String repayStatusName;
private String approvalStatusName;
}
...@@ -62,4 +62,13 @@ public interface IFastDFSService { ...@@ -62,4 +62,13 @@ public interface IFastDFSService {
* @throws IOException * @throws IOException
*/ */
byte[] downloadFile(String path) throws IOException; byte[] downloadFile(String path) throws IOException;
/**
* 转成一个临时可用的url
*
* @param path
* @return
* @throws IOException
*/
String toUrl(String path) throws IOException;
} }
package cn.quantgroup.customer.service;
import cn.quantgroup.customer.rest.param.vcc.OfflineRepaySubmitParam;
import cn.quantgroup.customer.rest.param.vcc.UserPreRepayInfoQuery;
import cn.quantgroup.customer.rest.vo.JsonResult;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
public interface IVccService {
JsonResult queryPage(UserPreRepayInfoQuery query) throws Exception;
JsonResult queryRepayCalDetail(String uniqueId,Integer repayType) throws Exception;
void saveSubmitRecord(OfflineRepaySubmitParam param,String token) throws Exception;
OfflineRepaySubmitParam approvalQuery(String serialNo) throws Exception;
JsonResult queryApprovalRecord(String serialNo) throws Exception;
void approvalResult( String serialNo, String remark, Integer status ,String token) throws Exception;
Map<String,String> fileUpload(MultipartFile file) throws Exception;
JsonResult queryApplyRecord(UserPreRepayInfoQuery query) throws Exception;
void saveApprovalRecord( String serialNo, String remark, Integer status,String token) throws Exception;
}
package cn.quantgroup.customer.service.ftp;
import cn.quantgroup.customer.exception.BusinessException;
import cn.quantgroup.customer.model.ftp.FileInfo;
import cn.quantgroup.customer.model.ftp.ServerInfo;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import static com.jcraft.jsch.ChannelSftp.SSH_FX_NO_SUCH_FILE;
@Slf4j
public class AbstractFtpService implements IFtpService {
private static final int SO_TIME_OUT = 60 * 1000; // 超时时间
private static final int TIME_OUT = 15 * 1000;
@Override
public Object send(Object request) {
return null;
}
@Override
public boolean send(FileInfo fileInfo, ServerInfo serverInfo, int retryTime) {
String path = fileInfo.getFilePath();
byte[] fileBytes = fileInfo.getFileBytes();
String fileName = fileInfo.getFileName();
if (StringUtils.isBlank(fileName)) {
throw new RuntimeException("文件名不能为空");
}
if (fileBytes == null) {
throw new RuntimeException("文件内容不能为空");
}
log.info("AbstractFtpService send fileName={}", fileName);
JSch jsch = null;
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
/**
* 方法返回值
*/
boolean result = Boolean.FALSE;
try {
jsch = new JSch();
session = jsch.getSession(serverInfo.getUsername(), serverInfo.getHost(), serverInfo.getPort());
session.setPassword(serverInfo.getPassword().getBytes(Charset.forName("ISO-8859-1")));
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setTimeout(SO_TIME_OUT);
log.info("连接SFTP服务器host={},port={}", serverInfo.getHost(), serverInfo.getPort());
session.connect(TIME_OUT);
channel = session.openChannel("sftp");
channel.connect();
channelSftp = (ChannelSftp)channel;
log.info("SFTPclient打开channel...");
InputStream input = null;
if (!session.isConnected() || !channelSftp.isConnected()) {
log.error("SFTPchannel已经关闭");
throw new BusinessException("SFTPchannel已经关闭");
}
// 目录不存在则创建
SftpATTRS exist = null;
try {
exist = channelSftp.lstat(serverInfo.getDirectory().concat(path));
} catch (SftpException e) {
log.info("路径不存在{},exist={}", serverInfo.getDirectory().concat(path),exist);
}
if (exist == null && StringUtils.isNotBlank(path)) {
path = serverInfo.getDirectory().concat(path);
createPath(path, channelSftp);
} else if (StringUtils.isBlank(path)) {
path = serverInfo.getDirectory();
} else {
path = serverInfo.getDirectory().concat(path);
}
log.info("SFTP.client.切换到目录={}", path);
channelSftp.cd(path);
log.info("SFTP.client.切换到目录成功={}", path);
input = new ByteArrayInputStream(fileBytes);
// 重试标上传志位
boolean retry = Boolean.TRUE;
int alreadyTryTime = 0;
log.info("开始上传文件");
// 发生异常,重试三次
while (retry && alreadyTryTime <= retryTime) {
try {
channelSftp.put(input, fileName);
log.info("SFTP.client.上传成功 目录={} 文件名={}", path, fileName);
result = Boolean.TRUE;
retry = Boolean.FALSE;
} catch (Exception e) {
log.error("SFTP文件上传失败 filename:{},alreadyTryTime:{},e:{}", fileName, alreadyTryTime, e);
try {
Thread.sleep(300);
} catch (InterruptedException interruptedException) {
}
alreadyTryTime++;
}
}
if (!result) {
throw new BusinessException("SFTP服务器异常!");
}
if (channelSftp != null) {
channelSftp.disconnect();
}
if (channel != null) {
channel.disconnect();
}
if (session != null) {
session.disconnect();
}
} catch (JSchException e) {
log.error("JSchException fileName={},e={}", fileName, ExceptionUtils.getStackTrace(e));
throw new BusinessException("SFTP创建连接失败, 信息="+ e);
} catch (SftpException e) {
log.error("SftpException fileName={},e={}", fileName, ExceptionUtils.getStackTrace(e));
throw new BusinessException("SFTP.client.操作失败");
}
return result;
}
protected void createPath(String path, ChannelSftp channelSftp) throws SftpException {
String[] folders = path.split("/");
for (String folder : folders) {
if (folder.length() > 0) {
try {
channelSftp.cd(folder);
} catch (SftpException e) {
try {
channelSftp.mkdir(folder);
} catch (SftpException e1) {
log.info("创建失败,path:{}, exception:{}", path, ExceptionUtils.getStackTrace(e1));
}
channelSftp.cd(folder);
}
}
}
}
@Override
public byte[] down(String fullName, ServerInfo serverInfo, int retryTime) throws Exception {
ByteArrayOutputStream fileOutputStream = new ByteArrayOutputStream();
JSch jsch;
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
try {
jsch = new JSch();
session = jsch.getSession(serverInfo.getUsername(), serverInfo.getHost(), serverInfo.getPort());
session.setPassword(serverInfo.getPassword().getBytes(Charset.forName("ISO-8859-1")));
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setTimeout(SO_TIME_OUT);
log.info("连接 SFTP 服务器 " + serverInfo.getHost() + ":" + serverInfo.getPort());
session.connect(TIME_OUT);
channel = session.openChannel("sftp");
channel.connect();
channelSftp = (ChannelSftp)channel;
log.info("SFTP client 打开 channel ...");
if (channelSftp == null || session == null || !session.isConnected() || !channelSftp.isConnected()) {
log.warn("SFTP channel 已经关闭");
throw new BusinessException("SFTP channel 已经关闭");
}
channelSftp.get(fullName, fileOutputStream);
byte[] data = fileOutputStream.toByteArray();
if (data == null || data.length < 2) {
log.warn("SFTP.client.下载回来的文件长度不对!文件名={}", fullName);
return null;
}
log.info("SFTP.client.下载成功 文件名={}", fullName);
return data;
} catch (JSchException e) {
log.warn("SFTP.client.创建连接失败");
throw new BusinessException("SFTP创建连接失败, 信息=" + e);
} catch (SftpException e) {
log.warn("SFTP.client.操作失败, 信息exception=", e);
if (e.id == SSH_FX_NO_SUCH_FILE) {
throw new FileNotFoundException("file not found " + fullName);
}
throw new BusinessException("SFTP.client.操作失败");
} finally {
if (channelSftp != null) {
channelSftp.disconnect();
}
if (channel != null) {
channel.disconnect();
}
if (session != null) {
session.disconnect();
}
}
}
@Override
public List<String> listDirectory(ServerInfo serverInfo) throws Exception {
JSch jsch;
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
try {
jsch = new JSch();
session = jsch.getSession(serverInfo.getUsername(), serverInfo.getHost(), serverInfo.getPort());
session.setPassword(serverInfo.getPassword().getBytes(Charset.forName("ISO-8859-1")));
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setTimeout(SO_TIME_OUT);
log.info("连接 SFTP 服务器 " + serverInfo.getHost() + ":" + serverInfo.getPort());
session.connect(TIME_OUT);
channel = session.openChannel("sftp");
channel.connect();
channelSftp = (ChannelSftp)channel;
log.info("SFTP client 打开 channel ...");
if (channelSftp == null || session == null || !session.isConnected() || !channelSftp.isConnected()) {
log.warn("SFTP channel 已经关闭");
throw new BusinessException("SFTP channel 已经关闭");
}
List<String> fileNameList = new ArrayList<>();
Vector<ChannelSftp.LsEntry> fileNameVector = channelSftp.ls(serverInfo.getDirectory());
for(ChannelSftp.LsEntry lsEntry : fileNameVector){
if(lsEntry.getFilename().equals(".") || lsEntry.getFilename().equals("..")){
continue;
}
fileNameList.add(lsEntry.getFilename());
}
return fileNameList;
} catch (JSchException e) {
log.warn("SFTP.client.创建连接失败");
throw new BusinessException("SFTP创建连接失败, 信息={}" + e);
} catch (SftpException e) {
log.warn("SFTP.client.操作失败, 信息exception=", e);
if (e.id == SSH_FX_NO_SUCH_FILE) {
throw new FileNotFoundException("directory not found " + serverInfo.getDirectory());
}
throw new BusinessException("SFTP.client.操作失败");
} finally {
if (channelSftp != null) {
channelSftp.disconnect();
}
if (channel != null) {
channel.disconnect();
}
if (session != null) {
session.disconnect();
}
}
}
}
package cn.quantgroup.customer.service.ftp;
import cn.quantgroup.customer.model.ftp.FileInfo;
import cn.quantgroup.customer.model.ftp.ServerInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Map;
/**
* @author yexiong.wang
* @date 2022/02/27
*/
@Slf4j
@Service("CustomerSftpServiceImpl")
public class CustomerSftpServiceImpl extends AbstractFtpService implements IFtpService {
//由于原定使用的没有使用,先直接给定默认值1
@Value("${customer.sftp.user:1}")
private String username;
@Value("${customer.sftp.password:1}")
private String password;
@Value("${customer.sftp.host:1}")
private String host;
@Value("${customer.sftp.directory:1}")
private String directory;
@Value("${customer.sftp.port:1}")
private int port;
/**
* @param request 请求参数对象
* @param retryTime 上传失败重试次数
* @return ture:上传成功,false:上传失败
* @throws Exception
*/
@Override
public Boolean send(Object request, int retryTime) throws Exception {
String fileName = "";
String path = "";
byte[] fileBytes = null;
if (request instanceof Map) {
fileName = (String) ((Map) request).get("fileName");
fileBytes = (byte[]) ((Map) request).get("fileBytes");
path = (String) ((Map) request).get("filePath");
}
if (StringUtils.isBlank(fileName)) {
throw new RuntimeException("文件名不能为空");
}
if (fileBytes == null) {
throw new RuntimeException("文件内容不能为空");
}
log.info("客服系统上传sftp, fileName:{}, path:{}", fileName, path);
FileInfo fileInfo = new FileInfo(fileName, fileBytes, path);
ServerInfo serverInfo = ServerInfo.builder()
.username(username)
.directory(directory)
.host(host)
.password(password)
.port(port)
.build();
send(fileInfo, serverInfo, 3);
return null;
}
@Override
public byte[] down(String fileName) throws IOException {
ServerInfo serverInfo = ServerInfo.builder()
.username(username).directory(directory)
.host(host).password(password)
.port(port)
.build();
byte[] result;
try {
fileName = directory.concat(fileName);
result = down(fileName, serverInfo, 1);
} catch (IOException ioEx) {
log.warn("客服系统下载文件,出现异常,fileName:{}, ex:{}", fileName, ExceptionUtils.getStackTrace(ioEx));
throw ioEx;
}
catch (Exception e) {
log.warn("客服系统下载文件,出现异常,fileName:{}, ex:{}", fileName, ExceptionUtils.getStackTrace(e));
throw new IOException("下载未知异常");
}
if (result == null) {
throw new IOException("文件为空");
}
return result;
}
}
package cn.quantgroup.customer.service.ftp;
import cn.quantgroup.customer.model.ftp.FileInfo;
import cn.quantgroup.customer.model.ftp.ServerInfo;
import org.apache.commons.lang3.NotImplementedException;
import java.io.IOException;
import java.util.List;
public interface IFtpService {
Object send(Object request);
/**
* @param request 请求参数对象
* @param retryTime 上传失败重试次数
* @return ture:上传成功,false:上传失败
* @throws Exception
*/
default Boolean send(Object request, int retryTime) throws Exception {
throw new NotImplementedException("send(Object request,int retryTime)方法没有实现!");
}
/**
* 文件下载
*
* @param fileName
* @return
* @throws IOException
*/
default byte[] down(String fileName) throws IOException {
throw new NotImplementedException("文件下载没有实现!");
}
/**
* SFTP 方式文件上传
*
* @param fileInfo  文件信息
* @param serverInfo  SFTP服务器信息
* @param retryTime 重试次数
* @return
* @throws Exception
*/
default boolean send(FileInfo fileInfo, ServerInfo serverInfo, int retryTime) throws Exception {
throw new NotImplementedException("send没有实现!");
}
/**
* 文件下载
*
* @param fullName 路径文件名称
* @param serverInfo 服务器信息
* @param retryTime 重试次数
* @return
* @throws Exception
*/
default byte[] down(String fullName, ServerInfo serverInfo, int retryTime) throws Exception {
throw new NotImplementedException("文件下载没有实现!");
}
/**
* 获取文件名列表
*
* @param serverInfo
* @return
* @throws Exception
*/
default List<String> listDirectory(ServerInfo serverInfo) throws Exception {
throw new NotImplementedException("查看目录下的所有文件没有实现!");
}
}
package cn.quantgroup.customer.service.impl; package cn.quantgroup.customer.service.impl;
import cn.quantgroup.customer.service.IFastDFSService; import cn.quantgroup.customer.service.IFastDFSService;
import cn.quantgroup.customer.util.ProtoCommon;
import com.github.tobato.fastdfs.domain.StorePath; import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.proto.storage.DownloadByteArray; import com.github.tobato.fastdfs.proto.storage.DownloadByteArray;
import com.github.tobato.fastdfs.service.FastFileStorageClient; import com.github.tobato.fastdfs.service.FastFileStorageClient;
...@@ -146,4 +147,31 @@ public class FastDFSServiceImpl implements IFastDFSService { ...@@ -146,4 +147,31 @@ public class FastDFSServiceImpl implements IFastDFSService {
}); });
return bytes; return bytes;
} }
/**
* 转成一个临时可用的url
* @param path
* @return
* @throws IOException
*/
@Override
public String toUrl(String path) throws IOException {
if (StringUtils.isBlank(path)) {
return null;
}
String fileName = path;
if (fileName.indexOf("/M") > 0) {
fileName = fileName.substring(fileName.indexOf("/M") + 1);
}
int lts = (int) (System.currentTimeMillis() / 1000);
// 初始化secret_key
try {
String token = ProtoCommon.getToken(fileName, lts, secretKey);
return fastDfsHttp + "/" + path + "?token=" + token + "&ts=" + lts;
} catch (Exception e) {
log.warn("生成FastDFS下载链接失败:path:{},", path, e);
throw new IOException("生成下载链接失败");
}
}
} }
package cn.quantgroup.customer.service.impl;
import cn.quantgroup.customer.entity.OfflineRepayOperateRecord;
import cn.quantgroup.customer.entity.OfflineRepaySubmitRecord;
import cn.quantgroup.customer.entity.OpUser;
import cn.quantgroup.customer.entity.QOfflineRepaySubmitRecord;
import cn.quantgroup.customer.enums.ApprovalStatus;
import cn.quantgroup.customer.enums.VccRepayStatusEnum;
import cn.quantgroup.customer.repo.OfflineRepayOperateRecordRepo;
import cn.quantgroup.customer.repo.OfflineRepaySubmitRecordRepo;
import cn.quantgroup.customer.rest.param.vcc.ApplyBill;
import cn.quantgroup.customer.rest.param.vcc.OfflineRepaySubmitParam;
import cn.quantgroup.customer.rest.param.vcc.UserPreRepayInfoQuery;
import cn.quantgroup.customer.rest.vo.JsonResult;
import cn.quantgroup.customer.rest.vo.vcc.QueryPreOfflineRepayVo;
import cn.quantgroup.customer.rest.vo.vcc.QuerySubmitRecordVo;
import cn.quantgroup.customer.service.IFastDFSService;
import cn.quantgroup.customer.service.IOpSystemService;
import cn.quantgroup.customer.service.IVccService;
import cn.quantgroup.customer.service.ftp.IFtpService;
import cn.quantgroup.customer.service.http.IHttpService;
import cn.quantgroup.customer.util.IdUtil;
import cn.quantgroup.user.retbean.XUser;
import cn.quantgroup.user.vo.UserSysResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.List;
@Slf4j
@Service
public class VccServiceImpl implements IVccService {
@Value("${vcc-talos.http}")
private String talosHttp;
@Autowired
private IHttpService httpService;
@Resource
private OfflineRepaySubmitRecordRepo offlineRepaySubmitRecordRepo;
@Resource
private OfflineRepayOperateRecordRepo offlineRepayOperateRecordRepo;
@Autowired
private IOpSystemService IOpSystemService;
@Autowired
private IFastDFSService fastDfsService;
@Autowired
private IFtpService ftpService;
@Autowired
private UserSdkImpl userSdk;
@Override
public JsonResult queryPage(UserPreRepayInfoQuery query) throws Exception{
String url = talosHttp + "/vcc/offline_pre_repay/query_page";
JSONObject param = JSONObject.parseObject(JSON.toJSONString(query));
log.info("queryPage | 开始请求talos获取预还款的详情,param={}",param);
String post = httpService.post(url, param);
log.info("queryPage | 请求talos结束,param={},result={}",param,post);
if (StringUtils.isBlank(post)){
log.error("queryPage | 请求talos异常,返回值为空,param={}",query);
return JsonResult.buildErrorStateResult("请求talos获取详情异常:没有请求通");
}
JSONObject jsonObject = JSONObject.parseObject(post);
if (!"0000".equals(jsonObject.getString("code")) || !"0000".equals(jsonObject.getString("businessCode"))){
log.error("queryPage | talos没有正确查询出结果:" + jsonObject.getString("msg"));
return JsonResult.buildErrorStateResult("talos没有正确查询出结果:" + jsonObject.getString("msg"));
}
JSONObject data = jsonObject.getJSONObject("data");
JSONArray list = data.getJSONArray("list");
List<QueryPreOfflineRepayVo> voList = new Gson().fromJson(list.toString(), new TypeToken<List<QueryPreOfflineRepayVo>>() {
}.getType());
for (int i = 0;i<voList.size();i++){
if (1 == query.getRepayType()){
ApplyBill applyBill = new ApplyBill();
applyBill.setBillId(Long.parseLong(voList.get(i).getUniqueId()));
applyBill.setAmount(voList.get(i).getCurrBall());
List<OfflineRepaySubmitRecord> byUserIdEqualsAndRepayTypeEquals = offlineRepaySubmitRecordRepo.findByUserIdEqualsAndRepayTypeEquals(voList.get(i).getUserId(), 1);
if (!CollectionUtils.isEmpty(byUserIdEqualsAndRepayTypeEquals)){
for (OfflineRepaySubmitRecord record:byUserIdEqualsAndRepayTypeEquals){
List<ApplyBill> billList = new Gson().fromJson(record.getBills(), new TypeToken<List<ApplyBill>>() {
}.getType());
log.info("billList={},applyBill={}",billList,applyBill);
if (billList.contains(applyBill)){
log.info("发现已经提交过了,补充流水号前:voList={}",voList);
voList.get(i).setSerialNo(record.getSerialNo());
voList.get(i).setApprovalStatus(record.getApprovalStatus());
log.info("发现已经提交过了,补充流水号后:voList={}",voList);
break;
}
}
}
}else {
OfflineRepaySubmitRecord firstByUniqueIdEquals = offlineRepaySubmitRecordRepo.findFirstByUniqueIdEquals(voList.get(i).getUniqueId());
if (Objects.nonNull(firstByUniqueIdEquals)){
voList.get(i).setSerialNo(firstByUniqueIdEquals.getSerialNo());
voList.get(i).setApprovalStatus(firstByUniqueIdEquals.getApprovalStatus());
}
}
}
Map<String,Object> map = new HashMap<>();
map.put("count",data.get("count"));
map.put("type",data.get("type"));
map.put("list",voList);
log.info("voList={}",voList);
return JsonResult.buildSuccessResult("请求成功",map);
}
@Override
public JsonResult queryRepayCalDetail(String uniqueId, Integer repayType) throws Exception {
String url = talosHttp + "/vcc/offline_pre_repay/detail?uniqueId=" + uniqueId + "&repayType=" + repayType;
log.info("queryRepayCalDetail | 开始请求talos,url={}",url);
String get = httpService.get(url);
log.info("queryRepayCalDetail | 请求talos结束,get={}",get);
if (StringUtils.isBlank(get)){
log.error("queryRepayCalDetail | 请求talos异常,返回值为空");
return JsonResult.buildErrorStateResult("请求talos获取详情异常:没有请求通");
}
JSONObject jsonObject = JSONObject.parseObject(get);
if (!"0000".equals(jsonObject.getString("code")) || !"0000".equals(jsonObject.getString("businessCode"))){
log.error("queryRepayCalDetail | talos没有正确查询出结果:" + jsonObject.getString("msg"));
return JsonResult.buildErrorStateResult("talos没有正确查询出结果:" + jsonObject.getString("msg"));
}
JSONObject data = jsonObject.getJSONObject("data");
return JsonResult.buildSuccessResult("请求成功",data);
}
@Override
@Transactional
public void saveSubmitRecord(OfflineRepaySubmitParam param,String token) throws Exception{
String serialNo = IdUtil.generateSequenceNo();
if (1 == param.getRepayType()){
//月还账单
List<ApplyBill> list = param.getList();
List<OfflineRepaySubmitRecord> byUserIdEqualsAndRepayTypeEquals = offlineRepaySubmitRecordRepo.findByUserIdEqualsAndRepayTypeEqualsAndApprovalStatusNot(param.getUserId(), 1,2);
if (!CollectionUtils.isEmpty(byUserIdEqualsAndRepayTypeEquals)){
for (OfflineRepaySubmitRecord record:byUserIdEqualsAndRepayTypeEquals){
List<ApplyBill> billList = new Gson().fromJson(record.getBills(), new TypeToken<List<ApplyBill>>() {
}.getType());
if (!Collections.disjoint(list,billList)){
log.error("saveSubmitRecord | 提交时发现已经提交过了,请确认,newBills={},existBills={}",list.toString(),billList.toString());
throw new Exception("提交时发现已经提交过了,请确认,newBills="+list.toString()+",existBills="+billList.toString());
}
}
}
OfflineRepaySubmitRecord record = new OfflineRepaySubmitRecord();
BeanUtils.copyProperties(param,record);
record.setSerialNo(serialNo);
record.setBills(JSONObject.toJSONString(list));
String replace = param.getCredentialsAddress().toString().replace("[", "").replace("]", "");
record.setCredentialsAddress(replace);
record.setApprovalStatus(0);
offlineRepaySubmitRecordRepo.save(record);
}else {
OfflineRepaySubmitRecord firstByUniqueIdEquals = offlineRepaySubmitRecordRepo.findFirstByUniqueIdEqualsAndApprovalStatusNot(param.getUniqueId(),2);
if (Objects.nonNull(firstByUniqueIdEquals)){
log.error("saveSubmitRecord | 提交时发现已经提交过了,请确认,uniqueId={}",param.getUniqueId());
throw new Exception("提交时发现已经提交过了,请确认,uniqueId="+param.getUniqueId());
}
OfflineRepaySubmitRecord record = new OfflineRepaySubmitRecord();
BeanUtils.copyProperties(param,record);
record.setSerialNo(serialNo);
String replace = param.getCredentialsAddress().toString().replace("[", "").replace("]", "");
record.setCredentialsAddress(replace);
record.setApprovalStatus(0);
offlineRepaySubmitRecordRepo.save(record);
}
//保存操作人记录
saveApprovalRecord(serialNo,"", 0 ,token);
}
@Override
public OfflineRepaySubmitParam approvalQuery(String serialNo) throws Exception {
OfflineRepaySubmitRecord bySerialNoEquals = offlineRepaySubmitRecordRepo.findBySerialNoEquals(serialNo);
if (Objects.isNull(bySerialNoEquals)){
log.error("approvalQuery | 没有查询到这条申请记录,请确认:serialNo = {}",serialNo);
throw new Exception("没有查询到这条申请记录,请确认:serialNo = " + serialNo);
}
OfflineRepaySubmitParam param = new OfflineRepaySubmitParam();
BeanUtils.copyProperties(bySerialNoEquals,param);
List<ApplyBill> billList = new Gson().fromJson(bySerialNoEquals.getBills(), new TypeToken<List<ApplyBill>>() {
}.getType());
param.setList(billList);
String[] split = bySerialNoEquals.getCredentialsAddress().split(",");
List<String> list = Arrays.asList(split);
// List<String> addressList = new ArrayList<>();
// for (String baseUrl:list){
//// String viewUrl = fastDfsService.toUrl(baseUrl);
//// addressList.add(viewUrl);
// byte[] down = ftpService.down(baseUrl);
// addressList.add(Base64.getEncoder().encodeToString(down));
// }
param.setCredentialsAddress(list);
return param;
}
@Override
public JsonResult queryApprovalRecord(String serialNo) throws Exception {
List<OfflineRepayOperateRecord> bySerialNoEquals = offlineRepayOperateRecordRepo.findBySerialNoEquals(serialNo);
return JsonResult.buildSuccessResult("请求成功",bySerialNoEquals);
}
@Override
@Transactional
public void approvalResult(String serialNo, String remark, Integer status ,String token) throws Exception {
OfflineRepaySubmitRecord bySerialNoEquals = offlineRepaySubmitRecordRepo.findBySerialNoEqualsAndApprovalStatusEquals(serialNo,0);
if (Objects.isNull(bySerialNoEquals)){
log.error("approvalQuery | 没有查询到这条申请记录,请确认:serialNo = {}",serialNo);
throw new Exception("没有查询到这条申请记录,请确认:serialNo = " + serialNo);
}
if ( 0 == status){
//审批拒绝
bySerialNoEquals.setApprovalStatus(2);
offlineRepaySubmitRecordRepo.save(bySerialNoEquals);
saveApprovalRecord(serialNo,remark,2,token);
}else if (1== status){
//审批通过
String url = "";
// String phone = bySerialNoEquals.getPhone();
// UserSysResult<XUser> userByPhoneNo = userSdk.getService().findUserByPhoneNo(phone);
// if (userByPhoneNo == null || !userByPhoneNo.isSuccess() || userByPhoneNo.getData() == null) {
// throw new RuntimeException("用户中心接口findUserDetailByPhone返回失败");
// }
if ( 1 == bySerialNoEquals.getRepayType()){
//月还账单
List<ApplyBill> billList = new Gson().fromJson(bySerialNoEquals.getBills(), new TypeToken<List<ApplyBill>>() {
}.getType());
StringBuilder stringBuilder = new StringBuilder();
for (ApplyBill applyBill:billList){
stringBuilder.append(applyBill.getBillId()).append(",");
}
String billNo = stringBuilder.substring(0,stringBuilder.lastIndexOf(","));
url = talosHttp + "/vcc/repay/offlineRepay?userId=" + bySerialNoEquals.getUserId() + "&amount=" + bySerialNoEquals.getAmount() + "&billNo=" + billNo;
}else {
//提前结清
url = talosHttp + "/vcc/offline_pre_repay/repay?userId=" + bySerialNoEquals.getUserId() + "&amount=" + bySerialNoEquals.getAmount()
+ "&repayType=" + bySerialNoEquals.getRepayType() + "&uniqueId=" + bySerialNoEquals.getUniqueId();
}
log.info("queryRepayCalDetail | 开始请求talos,url={}",url);
String get = httpService.get(url);
log.info("queryRepayCalDetail | 请求talos结束,get={}",get);
if (StringUtils.isBlank(get)){
log.error("queryRepayCalDetail | 请求talos异常,返回值为空");
throw new Exception("请求talos异常:没有请求通");
}
JSONObject jsonObject = JSONObject.parseObject(get);
if (!"0000".equals(jsonObject.getString("code")) || !"0000".equals(jsonObject.getString("businessCode"))){
log.error("queryRepayCalDetail | 请求talos处理失败,msg={}",jsonObject.getString("msg"));
throw new Exception("请求talos处理失败:"+jsonObject.getString("msg"));
}
bySerialNoEquals.setApprovalStatus(1);
offlineRepaySubmitRecordRepo.save(bySerialNoEquals);
saveApprovalRecord(serialNo,remark,1,token);
}
}
@Override
public Map<String,String> fileUpload(MultipartFile file) throws Exception {
// String name = file.getOriginalFilename();
// log.info("fileUpload | filename={}",name);
// String substring = name.substring(name.lastIndexOf(".") + 1);
// String baseUrl = fastDfsService.uploadFile(file.getBytes(), substring);
// String viewUrl = fastDfsService.toUrl(baseUrl);
// Map<String,String> map = new HashMap<>();
// map.put("baseUrl",baseUrl);
// map.put("viewUrl",viewUrl);
// return map;
String fileName = file.getOriginalFilename();
byte[] bytes = file.getBytes();
Map<String, Object> paramMap = new HashMap<>(8);
paramMap.put("fileName", fileName);
paramMap.put("fileBytes", bytes);
String filePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + "/";
paramMap.put("filePath", filePath);
ftpService.send(paramMap, 3);
Map<String,String> map = new HashMap<>();
map.put("base64",Base64.getEncoder().encodeToString(bytes));
map.put("url",filePath + fileName);
return map;
}
@Override
public JsonResult queryApplyRecord(UserPreRepayInfoQuery query) throws Exception {
BooleanExpression booleanExpression = Expressions.asBoolean(true).isTrue();
String phone = "";
if (StringUtils.isNotBlank(query.getUserId())){
log.info("userSdk={}",userSdk);
UserSysResult<XUser> userByUserId = userSdk.getService().findUserByUserId(Long.getLong(query.getUserId()));
if (userByUserId == null || !userByUserId.isSuccess() || userByUserId.getData() == null) {
log.info("queryApplyRecord | 查询用户中心失败");
}else {
phone = userByUserId.getData().getPhoneNo();
}
}
if (StringUtils.isNotBlank(query.getPhone())){
phone = query.getPhone();
}
if (StringUtils.isNotBlank(phone)){
booleanExpression = booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.phone.eq(phone));
}
if (query.getApprovalStatus() != null){
booleanExpression = booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.approvalStatus.eq(query.getApprovalStatus()));
}
if (query.getRepayType() != null){
booleanExpression = booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.repayType.eq(query.getRepayType()));
}
if (StringUtils.isNotBlank(query.getOrderNo())){
booleanExpression = booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.uniqueId.eq(query.getOrderNo()));
}
if (StringUtils.isNotBlank(query.getBillId())){
if (1 == query.getRepayType()){
booleanExpression = booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.bills.contains(query.getBillId()));
}else {
booleanExpression = booleanExpression.and(QOfflineRepaySubmitRecord.offlineRepaySubmitRecord.uniqueId.eq(query.getBillId()));
}
}
long count = offlineRepaySubmitRecordRepo.count(booleanExpression);
int offset = (query.getPageIndex() -1) * query.getPageSize();
Page<OfflineRepaySubmitRecord> plantPage = offlineRepaySubmitRecordRepo.findAll(booleanExpression, new PageRequest(offset, query.getPageSize()));
List<OfflineRepaySubmitRecord> content = plantPage.getContent();
List<QuerySubmitRecordVo> submitRecordVoList = new ArrayList<>();
for (OfflineRepaySubmitRecord record : content){
QuerySubmitRecordVo submitRecordVo = new QuerySubmitRecordVo();
BeanUtils.copyProperties(record,submitRecordVo);
submitRecordVo.setRepayStatusName(VccRepayStatusEnum.getDescByValue(submitRecordVo.getRepayStatus()));
submitRecordVo.setApprovalStatusName(ApprovalStatus.getDescByValue(submitRecordVo.getApprovalStatus()));
if ( 1 == submitRecordVo.getRepayType()) {
//月还账单
List<ApplyBill> billList = new Gson().fromJson(submitRecordVo.getBills(), new TypeToken<List<ApplyBill>>() {
}.getType());
StringBuilder stringBuilder = new StringBuilder();
for (ApplyBill applyBill : billList) {
stringBuilder.append(applyBill.getBillId()).append(",");
}
String billNo = stringBuilder.substring(0, stringBuilder.lastIndexOf(","));
submitRecordVo.setUniqueId(billNo);
}
submitRecordVoList.add(submitRecordVo);
}
Map<String,Object> map = new HashMap<>();
map.put("count",count);
map.put("type",query.getRepayType());
map.put("list",submitRecordVoList);
return JsonResult.buildSuccessResult("请求成功",map);
}
@Override
public void saveApprovalRecord(String serialNo, String remark, Integer status, String token) throws Exception {
JsonResult<OpUser> opUserResult = IOpSystemService.findUserByToken(token, null);
if (Objects.isNull(opUserResult) || !opUserResult.isSuccess()) {
log.error("根据token查询不到用户信息 token:{}", token);
return;
} else {
OpUser opUser = opUserResult.getData();
OfflineRepayOperateRecord record = new OfflineRepayOperateRecord();
record.setSerialNo(serialNo);
record.setOperateAccount(opUser.getUser());
record.setOperateName(opUser.getName());
if (0 == status){
record.setOperateContent("已提交");
}else if (1 == status){
record.setOperateContent("审批通过");
}else if (2 == status){
record.setOperateContent("审批拒绝");
}
record.setOperateTime(new Date());
record.setRemark(remark);
offlineRepayOperateRecordRepo.save(record);
}
}
}
package cn.quantgroup.customer.util;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.*;
import java.util.Calendar;
public class IdUtil {
/** .log */
private final static Logger logger = LoggerFactory.getLogger(IdUtil.class);
/** The FieldPosition. */
private static final FieldPosition HELPER_POSITION = new FieldPosition(0);
/** This Format for format the data to special format. */
private final static Format dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
/** This Format for format the number to special format. */
private final static NumberFormat numberFormat = new DecimalFormat("000");
/** This int is the sequence number ,the default value is 0. */
private static int seq = 0;
private static final int MAX = 999;
/**
* 时间格式生成序列
*
* @return String
*/
public static String generateSequenceNo() {
return generateSequenceNo("Q");
}
/**
* 时间格式生成序列
*
* @return String
*/
public static synchronized String generateSequenceNo(String prefix) {
Calendar rightNow = Calendar.getInstance();
StringBuffer sb = new StringBuffer();
dateFormat.format(rightNow.getTime(), sb, HELPER_POSITION);
numberFormat.format(seq, sb, HELPER_POSITION);
if (seq == MAX) {
seq = 0;
} else {
seq++;
}
if(StringUtils.isEmpty(prefix)){
prefix = "C";
}
String ip = IpAddrUtils.getHostIp();
Integer ipValue = Integer.parseInt(ip.split("\\.")[ip.split("\\.").length - 1]);
StringBuffer ipStr = new StringBuffer();
numberFormat.format(ipValue,ipStr,HELPER_POSITION);
String idNo = prefix + sb.toString() + ipStr.toString();
logger.debug("THE SQUENCE IS :" + idNo);
return idNo;
}
public static void main(String[] args) {
// for (int i = 0; i < 1000; i++) {
// System.out.println(generateSequenceNo());
// }
System.out.println(System.currentTimeMillis());
//System.out.println(dateFormat.format(Calendar.getInstance().getTime().getTime(), new StringBuffer(), HELPER_POSITION));
}
}
package cn.quantgroup.customer.util;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
@Slf4j
public class IpAddrUtils {
private final static String UNKNOWN = "unknown";
public static String getIpAddr(HttpServletRequest request) {
try {
StringBuffer sb = new StringBuffer();
Enumeration<String> er = request.getHeaderNames();
while (er.hasMoreElements()) {
String name = er.nextElement();
String value = request.getHeader(name);
sb.append(name).append("=").append(value).append(";");
}
log.info("获取请求Header: " + sb.toString());
} catch (Exception e) {
log.error("获取请求Header: " + e.getMessage());
}
String ip = request.getHeader("X-Forwarded-For");
if (ip != null && ip.length() != 0 && !UNKNOWN.equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个ip值,第一个ip才是真实ip
if (ip.contains(",")) {
ip = ip.split(",")[0];
}
}
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.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
public static String getHostIp() {
String sIP = "";
InetAddress ip = null;
try {
boolean bFindIP = false;
Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
while (netInterfaces.hasMoreElements()) {
if (bFindIP) {
break;
}
NetworkInterface ni = netInterfaces.nextElement();
Enumeration<InetAddress> ips = ni.getInetAddresses();
while (ips.hasMoreElements()) {
ip = ips.nextElement();
if (!ip.isLoopbackAddress() && ip.getHostAddress().matches("(\\d{1,3}\\.){3}\\d{1,3}")) {
bFindIP = true;
break;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
if (null != ip) {
sIP = ip.getHostAddress();
}
return sIP;
}
}
package cn.quantgroup.customer.util;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException;
/**
* protocol common functions
*
* @author jie.feng
*/
public class ProtoCommon {
private ProtoCommon() {
}
/**
* md5 function
*
* @param source the input buffer
* @return md5 string
*/
public static String md5(byte[] source) throws NoSuchAlgorithmException {
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
md.update(source);
byte tmp[] = md.digest();
char str[] = new char[32];
int k = 0;
for (int i = 0; i < 16; i++) {
str[k++] = hexDigits[tmp[i] >>> 4 & 0xf];
str[k++] = hexDigits[tmp[i] & 0xf];
}
return new String(str);
}
/**
* get token for file URL
*
* @param remote_filename the filename return by FastDFS server
* @param ts unix timestamp, unit: second
* @param secret_key the secret key
* @return token string
*/
public static String getToken(String remote_filename, int ts, String secret_key) throws UnsupportedEncodingException, NoSuchAlgorithmException {
byte[] bsFilename = remote_filename.getBytes(Charset.defaultCharset());
byte[] bsKey = secret_key.getBytes(Charset.defaultCharset());
byte[] bsTimestamp = (new Integer(ts)).toString().getBytes(Charset.defaultCharset());
byte[] buff = new byte[bsFilename.length + bsKey.length + bsTimestamp.length];
System.arraycopy(bsFilename, 0, buff, 0, bsFilename.length);
System.arraycopy(bsKey, 0, buff, bsFilename.length, bsKey.length);
System.arraycopy(bsTimestamp, 0, buff, bsFilename.length + bsKey.length, bsTimestamp.length);
return md5(buff);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment