feat(payment): 优化支付请求参数处理与商品列表接口

- 移除CheckoutRequestDTO中accId和sign字段的必填校验
- 支持从配置文件自动填充accId和signType字段
- 签名sign字段改为后端自动生成
- 新增商品列表查询接口GET /products/list
- 实现listProducts服务方法,支持分页和状态过滤
- 添加详细的日志记录和异常处理
- 修复启动时devtools导致的静默退出问题
- 优化数字类型参数转换异常处理
This commit is contained in:
2025-12-22 15:21:27 +08:00
parent f0e78c0814
commit a38af35ac5
15 changed files with 1897 additions and 5 deletions

View File

@@ -1080,3 +1080,364 @@ Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No q
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:769)
... 23 common frames omitted
2025-12-22 13:15:34.660 [main] ERROR com.mtkj.mtkjpay.MtkjpayApplication -
╔══════════════════════════════════════════════════════════╗
║ ║
║ ❌ MTKJ PAY 支付系统启动失败! ❌ ║
║ ║
╚══════════════════════════════════════════════════════════╝
org.springframework.boot.devtools.restart.SilentExitExceptionHandler$SilentExitException: null
at org.springframework.boot.devtools.restart.SilentExitExceptionHandler.exitCurrentThread(SilentExitExceptionHandler.java:92)
at org.springframework.boot.devtools.restart.Restarter.immediateRestart(Restarter.java:179)
at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:163)
at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:532)
at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationStartingEvent(RestartApplicationListener.java:98)
at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationEvent(RestartApplicationListener.java:51)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:178)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:171)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:149)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:137)
at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:75)
at org.springframework.boot.SpringApplicationRunListeners.lambda$starting$0(SpringApplicationRunListeners.java:54)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:54)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at com.mtkj.mtkjpay.MtkjpayApplication.main(MtkjpayApplication.java:33)
2025-12-22 13:39:14.468 [http-nio-8082-exec-1] ERROR com.mtkj.mtpay.exception.GlobalExceptionHandler - 运行时异常
org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; For input string: "list"
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.convertIfNecessary(AbstractNamedValueMethodArgumentResolver.java:292)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:135)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:218)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:171)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:917)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:829)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:340)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:842)
Caused by: java.lang.NumberFormatException: For input string: "list"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Long.parseLong(Long.java:711)
at java.base/java.lang.Long.valueOf(Long.java:1163)
at org.springframework.util.NumberUtils.parseNumber(NumberUtils.java:206)
at org.springframework.beans.propertyeditors.CustomNumberEditor.setAsText(CustomNumberEditor.java:115)
at org.springframework.beans.TypeConverterDelegate.doConvertTextValue(TypeConverterDelegate.java:438)
at org.springframework.beans.TypeConverterDelegate.doConvertValue(TypeConverterDelegate.java:411)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:160)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:80)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:53)
at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:860)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.convertIfNecessary(AbstractNamedValueMethodArgumentResolver.java:284)
... 48 common frames omitted
2025-12-22 13:39:19.318 [http-nio-8082-exec-2] ERROR com.mtkj.mtpay.exception.GlobalExceptionHandler - 运行时异常
org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; For input string: "list"
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.convertIfNecessary(AbstractNamedValueMethodArgumentResolver.java:292)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:135)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:218)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:171)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:917)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:829)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:340)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:842)
Caused by: java.lang.NumberFormatException: For input string: "list"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Long.parseLong(Long.java:711)
at java.base/java.lang.Long.valueOf(Long.java:1163)
at org.springframework.util.NumberUtils.parseNumber(NumberUtils.java:206)
at org.springframework.beans.propertyeditors.CustomNumberEditor.setAsText(CustomNumberEditor.java:115)
at org.springframework.beans.TypeConverterDelegate.doConvertTextValue(TypeConverterDelegate.java:438)
at org.springframework.beans.TypeConverterDelegate.doConvertValue(TypeConverterDelegate.java:411)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:160)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:80)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:53)
at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:860)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.convertIfNecessary(AbstractNamedValueMethodArgumentResolver.java:284)
... 48 common frames omitted
2025-12-22 13:40:27.113 [http-nio-8082-exec-3] ERROR com.mtkj.mtpay.exception.GlobalExceptionHandler - 运行时异常
org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; For input string: "list"
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.convertIfNecessary(AbstractNamedValueMethodArgumentResolver.java:292)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:135)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:218)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:171)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:917)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:829)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:340)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:842)
Caused by: java.lang.NumberFormatException: For input string: "list"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Long.parseLong(Long.java:711)
at java.base/java.lang.Long.valueOf(Long.java:1163)
at org.springframework.util.NumberUtils.parseNumber(NumberUtils.java:206)
at org.springframework.beans.propertyeditors.CustomNumberEditor.setAsText(CustomNumberEditor.java:115)
at org.springframework.beans.TypeConverterDelegate.doConvertTextValue(TypeConverterDelegate.java:438)
at org.springframework.beans.TypeConverterDelegate.doConvertValue(TypeConverterDelegate.java:411)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:160)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:80)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:53)
at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:860)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.convertIfNecessary(AbstractNamedValueMethodArgumentResolver.java:284)
... 48 common frames omitted
2025-12-22 13:40:56.127 [main] ERROR com.mtkj.mtkjpay.MtkjpayApplication -
╔══════════════════════════════════════════════════════════╗
║ ║
║ ❌ MTKJ PAY 支付系统启动失败! ❌ ║
║ ║
╚══════════════════════════════════════════════════════════╝
org.springframework.boot.devtools.restart.SilentExitExceptionHandler$SilentExitException: null
at org.springframework.boot.devtools.restart.SilentExitExceptionHandler.exitCurrentThread(SilentExitExceptionHandler.java:92)
at org.springframework.boot.devtools.restart.Restarter.immediateRestart(Restarter.java:179)
at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:163)
at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:532)
at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationStartingEvent(RestartApplicationListener.java:98)
at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationEvent(RestartApplicationListener.java:51)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:178)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:171)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:149)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:137)
at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:75)
at org.springframework.boot.SpringApplicationRunListeners.lambda$starting$0(SpringApplicationRunListeners.java:54)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:54)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at com.mtkj.mtkjpay.MtkjpayApplication.main(MtkjpayApplication.java:33)
2025-12-22 13:52:53.760 [main] ERROR com.mtkj.mtkjpay.MtkjpayApplication -
╔══════════════════════════════════════════════════════════╗
║ ║
║ ❌ MTKJ PAY 支付系统启动失败! ❌ ║
║ ║
╚══════════════════════════════════════════════════════════╝
org.springframework.boot.devtools.restart.SilentExitExceptionHandler$SilentExitException: null
at org.springframework.boot.devtools.restart.SilentExitExceptionHandler.exitCurrentThread(SilentExitExceptionHandler.java:92)
at org.springframework.boot.devtools.restart.Restarter.immediateRestart(Restarter.java:179)
at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:163)
at org.springframework.boot.devtools.restart.Restarter.initialize(Restarter.java:532)
at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationStartingEvent(RestartApplicationListener.java:98)
at org.springframework.boot.devtools.restart.RestartApplicationListener.onApplicationEvent(RestartApplicationListener.java:51)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:178)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:171)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:149)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:137)
at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:75)
at org.springframework.boot.SpringApplicationRunListeners.lambda$starting$0(SpringApplicationRunListeners.java:54)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:54)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at com.mtkj.mtkjpay.MtkjpayApplication.main(MtkjpayApplication.java:33)
2025-12-22 14:07:53.745 [http-nio-8082-exec-9] ERROR com.mtkj.mtpay.exception.GlobalExceptionHandler - 系统异常
org.springframework.web.servlet.resource.NoResourceFoundException: No static resource api/order.
at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:585)
at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:52)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:340)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:842)
2025-12-22 14:08:05.752 [http-nio-8082-exec-10] ERROR com.mtkj.mtpay.exception.GlobalExceptionHandler - 系统异常
org.springframework.web.servlet.resource.NoResourceFoundException: No static resource api/order.
at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:585)
at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:52)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:340)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:842)

File diff suppressed because one or more lines are too long

View File

@@ -83,7 +83,12 @@ public enum ResultCode {
/**
* 服务不可用
*/
SERVICE_UNAVAILABLE("5001", "服务不可用");
SERVICE_UNAVAILABLE("5001", "服务不可用"),
/**
* 业务错误
*/
BUSINESS_ERROR("6000", "业务错误");
/**
* 响应码

View File

@@ -0,0 +1,53 @@
package com.mtkj.mtpay.controller;
import com.mtkj.mtpay.common.Result;
import com.mtkj.mtpay.dto.request.CreateCustomerOrderRequestDTO;
import com.mtkj.mtpay.dto.response.CustomerOrderResponseDTO;
import com.mtkj.mtpay.service.CustomerOrderService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
/**
* 客户订单控制器
*/
@Slf4j
@RestController
@RequestMapping("/api/order")
@RequiredArgsConstructor
public class CustomerOrderController {
private final CustomerOrderService customerOrderService;
/**
* 创建客户订单
*/
@PostMapping
public Result<CustomerOrderResponseDTO> createOrder(@Valid @RequestBody CreateCustomerOrderRequestDTO request) {
log.info("创建客户订单请求:{}", request);
CustomerOrderResponseDTO order = customerOrderService.createOrder(request);
return Result.success("订单创建成功", order);
}
/**
* 根据订单号获取订单详情
*/
@GetMapping("/{orderNo}")
public Result<CustomerOrderResponseDTO> getOrderByOrderNo(@PathVariable String orderNo) {
log.info("获取订单详情,订单号:{}", orderNo);
CustomerOrderResponseDTO order = customerOrderService.getOrderByOrderNo(orderNo);
return Result.success(order);
}
/**
* 根据ID获取订单详情
*/
@GetMapping("/id/{id}")
public Result<CustomerOrderResponseDTO> getOrderById(@PathVariable Long id) {
log.info("获取订单详情订单ID{}", id);
CustomerOrderResponseDTO order = customerOrderService.getOrderById(id);
return Result.success(order);
}
}

View File

@@ -67,6 +67,16 @@ public class ProductController {
}
}
/**
* 获取商品列表
*/
@GetMapping("/list")
public Result<List<ProductResponseDTO>> listProducts() {
log.info("获取商品列表");
List<ProductResponseDTO> products = productService.listProducts();
return Result.success(products);
}
/**
* 获取商品详情页URL
*/

View File

@@ -13,9 +13,8 @@ import java.io.Serializable;
@Data
public class CheckoutRequestDTO implements Serializable {
@NotBlank(message = "商户店铺编号不能为空")
@Size(max = 64, message = "商户店铺编号长度不能超过64")
private String accId;
private String accId; // 可选,后端会自动从配置中获取
@NotBlank(message = "交易金额不能为空")
@Pattern(regexp = "^\\d+(\\.\\d{2})?$", message = "交易金额格式不正确,需保留两位小数")
@@ -49,9 +48,8 @@ public class CheckoutRequestDTO implements Serializable {
@Pattern(regexp = "^(MD5|SHA256)$", message = "签名类型必须为MD5或SHA256")
private String signType;
@NotBlank(message = "签名不能为空")
@Size(max = 255, message = "签名长度不能超过255")
private String sign;
private String sign; // 可选,后端会自动生成
@Size(max = 64, message = "商户用户ID长度不能超过64")
private String merchantUserId;

View File

@@ -0,0 +1,68 @@
package com.mtkj.mtpay.dto.request;
import jakarta.validation.constraints.*;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* 创建客户订单请求DTO
*/
@Data
public class CreateCustomerOrderRequestDTO implements Serializable {
@NotNull(message = "商品ID不能为空")
private Long productId;
@NotNull(message = "SKU ID不能为空")
private Long skuId;
@NotNull(message = "购买数量不能为空")
@Min(value = 1, message = "购买数量至少为1")
private Integer quantity;
// 客户信息
@NotBlank(message = "客户姓名不能为空")
@Size(max = 100, message = "客户姓名长度不能超过100")
private String customerName;
@NotBlank(message = "客户电话不能为空")
@Size(max = 20, message = "客户电话长度不能超过20")
private String customerPhone;
@Email(message = "邮箱格式不正确")
@Size(max = 100, message = "邮箱长度不能超过100")
private String customerEmail;
// 收货地址
@NotBlank(message = "收货人姓名不能为空")
@Size(max = 100, message = "收货人姓名长度不能超过100")
private String shippingName;
@NotBlank(message = "收货人电话不能为空")
@Size(max = 20, message = "收货人电话长度不能超过20")
private String shippingPhone;
@NotBlank(message = "收货国家不能为空")
@Size(max = 50, message = "收货国家长度不能超过50")
private String shippingCountry;
@Size(max = 50, message = "收货州/省长度不能超过50")
private String shippingState;
@NotBlank(message = "收货城市不能为空")
@Size(max = 50, message = "收货城市长度不能超过50")
private String shippingCity;
@NotBlank(message = "收货街道地址不能为空")
@Size(max = 200, message = "收货街道地址长度不能超过200")
private String shippingStreet;
@Size(max = 20, message = "收货邮编长度不能超过20")
private String shippingPostcode;
@Size(max = 500, message = "订单备注长度不能超过500")
private String remark;
}

View File

@@ -0,0 +1,42 @@
package com.mtkj.mtpay.dto.response;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 客户订单响应DTO
*/
@Data
public class CustomerOrderResponseDTO implements Serializable {
private Long id;
private String orderNo;
private Long productId;
private String productName;
private Long skuId;
private String skuName;
private Integer quantity;
private BigDecimal unitPrice;
private BigDecimal totalAmount;
private String currency;
private String status;
private String customerName;
private String customerPhone;
private String customerEmail;
private String shippingName;
private String shippingPhone;
private String shippingCountry;
private String shippingState;
private String shippingCity;
private String shippingStreet;
private String shippingPostcode;
private Long paymentOrderId;
private String paymentStatus;
private String remark;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,172 @@
package com.mtkj.mtpay.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 客户订单实体类
*/
@TableName(value = "customer_order")
@Data
public class CustomerOrder {
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 订单号(全局唯一)
*/
@TableField(value = "order_no", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String orderNo;
/**
* 商品ID
*/
@TableField(value = "product_id", jdbcType = org.apache.ibatis.type.JdbcType.BIGINT)
private Long productId;
/**
* 商品名称
*/
@TableField(value = "product_name", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String productName;
/**
* SKU ID
*/
@TableField(value = "sku_id", jdbcType = org.apache.ibatis.type.JdbcType.BIGINT)
private Long skuId;
/**
* SKU名称/描述
*/
@TableField(value = "sku_name", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String skuName;
/**
* 购买数量
*/
@TableField(value = "quantity", jdbcType = org.apache.ibatis.type.JdbcType.INTEGER)
private Integer quantity;
/**
* 单价
*/
@TableField(value = "unit_price", jdbcType = org.apache.ibatis.type.JdbcType.DECIMAL)
private BigDecimal unitPrice;
/**
* 订单总金额
*/
@TableField(value = "total_amount", jdbcType = org.apache.ibatis.type.JdbcType.DECIMAL)
private BigDecimal totalAmount;
/**
* 货币代码
*/
@TableField(value = "currency", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String currency;
/**
* 订单状态PENDING-待支付PAID-已支付SHIPPED-已发货COMPLETED-已完成CANCELLED-已取消
*/
@TableField(value = "status", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String status;
/**
* 客户姓名
*/
@TableField(value = "customer_name", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String customerName;
/**
* 客户电话
*/
@TableField(value = "customer_phone", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String customerPhone;
/**
* 客户邮箱
*/
@TableField(value = "customer_email", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String customerEmail;
/**
* 收货人姓名
*/
@TableField(value = "shipping_name", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String shippingName;
/**
* 收货人电话
*/
@TableField(value = "shipping_phone", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String shippingPhone;
/**
* 收货国家
*/
@TableField(value = "shipping_country", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String shippingCountry;
/**
* 收货州/省
*/
@TableField(value = "shipping_state", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String shippingState;
/**
* 收货城市
*/
@TableField(value = "shipping_city", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String shippingCity;
/**
* 收货街道地址
*/
@TableField(value = "shipping_street", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String shippingStreet;
/**
* 收货邮编
*/
@TableField(value = "shipping_postcode", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String shippingPostcode;
/**
* 关联的支付订单ID
*/
@TableField(value = "payment_order_id", jdbcType = org.apache.ibatis.type.JdbcType.BIGINT)
private Long paymentOrderId;
/**
* 支付状态UNPAID-未支付PAID-已支付FAILED-支付失败
*/
@TableField(value = "payment_status", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String paymentStatus;
/**
* 订单备注
*/
@TableField(value = "remark", jdbcType = org.apache.ibatis.type.JdbcType.VARCHAR)
private String remark;
/**
* 创建时间
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* 更新时间
*/
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,13 @@
package com.mtkj.mtpay.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mtkj.mtpay.entity.CustomerOrder;
import org.apache.ibatis.annotations.Mapper;
/**
* 客户订单Mapper接口
*/
@Mapper
public interface CustomerOrderMapper extends BaseMapper<CustomerOrder> {
}

View File

@@ -0,0 +1,32 @@
package com.mtkj.mtpay.service;
import com.mtkj.mtpay.dto.request.CreateCustomerOrderRequestDTO;
import com.mtkj.mtpay.dto.response.CustomerOrderResponseDTO;
/**
* 客户订单服务接口
*/
public interface CustomerOrderService {
/**
* 创建客户订单
* @param request 创建订单请求
* @return 订单响应
*/
CustomerOrderResponseDTO createOrder(CreateCustomerOrderRequestDTO request);
/**
* 根据订单号获取订单详情
* @param orderNo 订单号
* @return 订单响应
*/
CustomerOrderResponseDTO getOrderByOrderNo(String orderNo);
/**
* 根据ID获取订单详情
* @param id 订单ID
* @return 订单响应
*/
CustomerOrderResponseDTO getOrderById(Long id);
}

View File

@@ -3,6 +3,8 @@ package com.mtkj.mtpay.service;
import com.mtkj.mtpay.dto.request.CreateProductRequestDTO;
import com.mtkj.mtpay.dto.response.ProductResponseDTO;
import java.util.List;
/**
* 商品服务接口
*/
@@ -35,5 +37,11 @@ public interface ProductService {
* @return 商品ID
*/
Long getProductIdByLinkCode(String linkCode);
/**
* 获取商品列表
* @return 商品列表
*/
List<ProductResponseDTO> listProducts();
}

View File

@@ -0,0 +1,141 @@
package com.mtkj.mtpay.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mtkj.mtpay.common.ResultCode;
import com.mtkj.mtpay.dto.request.CreateCustomerOrderRequestDTO;
import com.mtkj.mtpay.dto.response.CustomerOrderResponseDTO;
import com.mtkj.mtpay.entity.CustomerOrder;
import com.mtkj.mtpay.entity.MtProduct;
import com.mtkj.mtpay.entity.MtProductSku;
import com.mtkj.mtpay.exception.BusinessException;
import com.mtkj.mtpay.mapper.CustomerOrderMapper;
import com.mtkj.mtpay.mapper.MtProductMapper;
import com.mtkj.mtpay.mapper.MtProductSkuMapper;
import com.mtkj.mtpay.service.CustomerOrderService;
import com.mtkj.mtpay.util.OrderIdGenerator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
/**
* 客户订单服务实现类
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class CustomerOrderServiceImpl implements CustomerOrderService {
private final CustomerOrderMapper customerOrderMapper;
private final MtProductMapper productMapper;
private final MtProductSkuMapper productSkuMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public CustomerOrderResponseDTO createOrder(CreateCustomerOrderRequestDTO request) {
log.info("创建客户订单商品ID: {}, SKU ID: {}, 数量: {}",
request.getProductId(), request.getSkuId(), request.getQuantity());
// 验证商品是否存在
MtProduct product = productMapper.selectById(request.getProductId());
if (product == null) {
log.warn("商品不存在商品ID: {}", request.getProductId());
throw new BusinessException(ResultCode.DATA_NOT_FOUND, "商品不存在");
}
// 验证SKU是否存在
MtProductSku sku = productSkuMapper.selectById(request.getSkuId());
if (sku == null || !sku.getProductId().equals(request.getProductId())) {
log.warn("SKU不存在或不属于该商品SKU ID: {}, 商品ID: {}",
request.getSkuId(), request.getProductId());
throw new BusinessException(ResultCode.DATA_NOT_FOUND, "SKU不存在");
}
// 验证库存
if (sku.getStock() == null || sku.getStock() < request.getQuantity()) {
log.warn("库存不足SKU ID: {}, 库存: {}, 需要: {}",
request.getSkuId(), sku.getStock(), request.getQuantity());
throw new BusinessException(ResultCode.BUSINESS_ERROR, "库存不足");
}
// 创建订单
CustomerOrder order = new CustomerOrder();
order.setOrderNo(OrderIdGenerator.generateMerchantTransactionId());
order.setProductId(request.getProductId());
order.setProductName(product.getName());
order.setSkuId(request.getSkuId());
order.setSkuName(sku.getSku());
order.setQuantity(request.getQuantity());
order.setUnitPrice(sku.getPrice());
order.setTotalAmount(sku.getPrice().multiply(new BigDecimal(request.getQuantity())));
order.setCurrency(sku.getCurrency());
order.setStatus("PENDING");
order.setPaymentStatus("UNPAID");
// 客户信息
order.setCustomerName(request.getCustomerName());
order.setCustomerPhone(request.getCustomerPhone());
order.setCustomerEmail(request.getCustomerEmail());
// 收货地址
order.setShippingName(request.getShippingName());
order.setShippingPhone(request.getShippingPhone());
order.setShippingCountry(request.getShippingCountry());
order.setShippingState(request.getShippingState());
order.setShippingCity(request.getShippingCity());
order.setShippingStreet(request.getShippingStreet());
order.setShippingPostcode(request.getShippingPostcode());
order.setRemark(request.getRemark());
// 保存订单
int result = customerOrderMapper.insert(order);
if (result <= 0) {
log.error("创建订单失败商品ID: {}", request.getProductId());
throw new BusinessException(ResultCode.SYSTEM_ERROR, "创建订单失败");
}
log.info("客户订单创建成功订单ID: {}, 订单号: {}", order.getId(), order.getOrderNo());
// 转换为响应DTO
CustomerOrderResponseDTO response = new CustomerOrderResponseDTO();
BeanUtils.copyProperties(order, response);
return response;
}
@Override
public CustomerOrderResponseDTO getOrderByOrderNo(String orderNo) {
log.debug("查询订单,订单号: {}", orderNo);
LambdaQueryWrapper<CustomerOrder> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(CustomerOrder::getOrderNo, orderNo);
CustomerOrder order = customerOrderMapper.selectOne(queryWrapper);
if (order == null) {
log.warn("订单不存在,订单号: {}", orderNo);
throw new BusinessException(ResultCode.DATA_NOT_FOUND, "订单不存在");
}
CustomerOrderResponseDTO response = new CustomerOrderResponseDTO();
BeanUtils.copyProperties(order, response);
return response;
}
@Override
public CustomerOrderResponseDTO getOrderById(Long id) {
log.debug("查询订单订单ID: {}", id);
CustomerOrder order = customerOrderMapper.selectById(id);
if (order == null) {
log.warn("订单不存在订单ID: {}", id);
throw new BusinessException(ResultCode.DATA_NOT_FOUND, "订单不存在");
}
CustomerOrderResponseDTO response = new CustomerOrderResponseDTO();
BeanUtils.copyProperties(order, response);
return response;
}
}

View File

@@ -2,6 +2,7 @@ package com.mtkj.mtpay.service.impl;
import com.mtkj.mtpay.common.ResultCode;
import com.mtkj.mtpay.common.constants.PaymentConstants;
import com.mtkj.mtpay.config.PingPongProperties;
import com.mtkj.mtpay.dto.request.CheckoutRequestDTO;
import com.mtkj.mtpay.dto.response.CheckoutResponseDTO;
import com.mtkj.mtpay.entity.PaymentOrder;
@@ -15,6 +16,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.util.Optional;
@@ -30,6 +32,7 @@ public class PaymentOrderServiceImpl implements PaymentOrderService {
private final PaymentOrderMapper paymentOrderMapper;
private final PaymentRecordMapper paymentRecordMapper;
private final PingPongPayService pingPongPayService;
private final PingPongProperties pingPongProperties;
@Override
@Transactional
@@ -45,6 +48,17 @@ public class PaymentOrderServiceImpl implements PaymentOrderService {
throw new BusinessException(ResultCode.ORDER_EXISTS);
}
// 填充accId和signType如果前端未提供从配置中获取
if (!StringUtils.hasText(request.getAccId())) {
request.setAccId(pingPongProperties.getAccId());
log.debug("使用配置中的accId: {}", request.getAccId());
}
if (!StringUtils.hasText(request.getSignType())) {
request.setSignType(pingPongProperties.getSignType());
log.debug("使用配置中的signType: {}", request.getSignType());
}
// sign字段由PingPongPayService自动生成不需要前端提供
// 创建订单实体
PaymentOrder order = new PaymentOrder();
order.setMerchantTransactionId(request.getMerchantTransactionId());
@@ -58,6 +72,7 @@ public class PaymentOrderServiceImpl implements PaymentOrderService {
order.setNotificationUrl(request.getNotificationUrl());
order.setRemark(request.getRemark());
order.setStatus(PaymentConstants.DEFAULT_ORDER_STATUS);
order.setAccId(request.getAccId());
// 调用PingPong API创建支付
CheckoutResponseDTO response = pingPongPayService.checkout(request);

View File

@@ -245,5 +245,73 @@ public class ProductServiceImpl implements ProductService {
log.debug("根据链接码获取商品ID成功链接码: {}, 商品ID: {}", linkCode, productId);
return productId;
}
@Override
public List<ProductResponseDTO> listProducts() {
log.debug("查询商品列表");
// 查询所有商品(排除已删除的)
LambdaQueryWrapper<MtProduct> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.ne(MtProduct::getStatus, "DELETED");
queryWrapper.orderByDesc(MtProduct::getCreateTime);
List<MtProduct> products = productMapper.selectList(queryWrapper);
log.debug("查询到商品数量: {}", products.size());
// 转换为响应DTO列表
List<ProductResponseDTO> result = new ArrayList<>();
for (MtProduct product : products) {
ProductResponseDTO dto = new ProductResponseDTO();
BeanUtils.copyProperties(product, dto);
// 处理主图解析JSON数组或使用单个URL
if (StringUtils.hasText(product.getMainImage())) {
try {
// 尝试解析为JSON数组
if (product.getMainImage().trim().startsWith("[")) {
List<String> mainImages = objectMapper.readValue(
product.getMainImage(),
new TypeReference<List<String>>() {}
);
dto.setMainImages(mainImages);
// 兼容第一个作为mainImage
if (!mainImages.isEmpty()) {
dto.setMainImage(mainImages.get(0));
}
} else {
// 单个URL
dto.setMainImage(product.getMainImage());
List<String> singleImageList = new ArrayList<>();
singleImageList.add(product.getMainImage());
dto.setMainImages(singleImageList);
}
} catch (Exception e) {
log.warn("解析商品主图失败使用原始值商品ID: {}", product.getId(), e);
dto.setMainImage(product.getMainImage());
List<String> singleImageList = new ArrayList<>();
singleImageList.add(product.getMainImage());
dto.setMainImages(singleImageList);
}
}
// 查询SKU列表用于获取销售地区信息
LambdaQueryWrapper<MtProductSku> skuWrapper = new LambdaQueryWrapper<>();
skuWrapper.eq(MtProductSku::getProductId, product.getId());
List<MtProductSku> skus = productSkuMapper.selectList(skuWrapper);
// 转换SKU为DTO列表页需要SKU的currency信息来显示销售地区
List<ProductResponseDTO.ProductSkuResponseDTO> skuDTOs = skus.stream().map(sku -> {
ProductResponseDTO.ProductSkuResponseDTO skuDTO = new ProductResponseDTO.ProductSkuResponseDTO();
BeanUtils.copyProperties(sku, skuDTO);
return skuDTO;
}).collect(Collectors.toList());
dto.setSkus(skuDTOs);
result.add(dto);
}
log.info("获取商品列表成功,商品数量: {}", result.size());
return result;
}
}