Spring-级联实体的引导验证 - 在 HttpResponse 中发送自定义错误

Spring-Boot Validation for Cascading Entity - Sending Custom Error in HttpResponse

我想发送我的自定义 ResponseEntity<> 作为我的 webService 的响应,其中包含错误的特定结构。

问题出在我的子实体上,我没有看到我正在尝试设置的自定义错误。

这些是我的 类 -

1.实体父级 (FplUser.java)

package com.tester.demojar.entities;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.validation.constraints.Size;

@Entity
@Table(name = "FPL_USER")
public class FplUser {

    public FplUser() {
    }
    
    public FplUser(String userName, String userPassword, char emailVerificationStatus) {
        this.emailVerificationStatus = emailVerificationStatus;
        this.userName = userName;
        this.userPassword = userPassword;
    }

    @Id
    @SequenceGenerator(name = "FPL_USER_SEQ", allocationSize = 1, initialValue = 100)
    @GeneratedValue(generator = "FPL_USER_SEQ", strategy = GenerationType.SEQUENCE)
    @Column(name = "JPA_ID")
    private long id;

    @Size(min = 5, message = "UserName minimum length = 5")
    @Column(name = "USER_NAME")
    private String userName;

    @Size(min = 8, message = "userPassword minimum length = 8")
    @Column(name = "USERPASSWORD")
    private String userPassword;

    @Column(name = "USER_EMAIL_VERIFICATION")
    private char emailVerificationStatus;
    
    @OneToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.REMOVE}, targetEntity = FplUserInfo.class, fetch = FetchType.LAZY, mappedBy = "fplUser")
    private FplUserInfo fplUserInfo;

2。实体子 (FplUserInfo.java)

package com.tester.demojar.entities;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;


@Entity
@Table(name = "FPL_USER_INFO")
public class FplUserInfo {
    
    @Id
    @SequenceGenerator(name = "FPL_USER_INFO_SEQ", allocationSize = 1, initialValue = 100)
    @GeneratedValue(generator = "FPL_USER_INFO_SEQ", strategy = GenerationType.SEQUENCE)
    @Column(name = "JPA_ID")
    long jpaId;
    
    @Min(value = 18, message = "Age should be minimum 18 Years")
    @Column(name = "AGE")
    int age;
    
    @Size(min = 2, message = "favouriteTeam minimum length = 2")
    @Column(name = "FAV_TEAM")
    String favouriteTeam;
    
    @JoinColumn(name = "FPL_USER_JPA_ID")
    @OneToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.LAZY)
    FplUser fplUser;

3。我的控制器 Class (UserRequestController.java)

package com.tester.demojar.controller;

import java.net.URI;
import java.util.List;
import java.util.Optional;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import com.tester.demojar.entities.FplUser;
import com.tester.demojar.exceptionHandling.FplUserException;
import com.tester.demojar.services.FplUserService;

@RestController
public class UserRequestController {
    
    @Autowired
    FplUserService fplUserService;
    
    @GetMapping("/user/{jpaId}")
    Optional<FplUser> getUserName(@PathVariable long jpaId) {
        Optional<FplUser> fplUser = fplUserService.getDetailsOfUserName(jpaId);
        System.out.println("fplUser +"+fplUser);
        if(fplUser.isEmpty()) {
            throw new FplUserException("id nahi mila-"+jpaId, HttpStatus.NOT_FOUND);
        }
        return fplUser;
    }
    @PostMapping("/user")
    ResponseEntity<Object> insertNewUser(@Valid @RequestBody FplUser fplUser) throws FplUserException{
        fplUser.getFplUserInfo().setFplUser(fplUser);
        FplUser newlyAddedFplUser = fplUserService.insertNewUser(fplUser);
        
        URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{jpaId}").buildAndExpand(newlyAddedFplUser.getId()).toUri();
        return ResponseEntity.created(location).build();
    }
    
}


4。我的自定义异常 (FplUserException.java)

package com.tester.demojar.exceptionHandling;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

public class FplUserException extends RuntimeException {

    private HttpStatus code;
    
    public FplUserException(String message) {
        super(message);
    }
    
    public FplUserException(String message, HttpStatus code) {
        super(message);
        this.code = code;
    }

    public HttpStatus getCode() {
        return code;
    }
    
}

5.我的服务响应处理异常 Class (FplAppResponseExceptionHandling.java)

package com.tester.demojar.exceptionHandling;

import java.util.Date;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
@RestController
public class FplAppResponseExceptionHandling extends ResponseEntityExceptionHandler{

    @ExceptionHandler(FplUserException.class)
    public final ResponseEntity<Object> handleUserNotFoundException(FplUserException ex, WebRequest request){
        FplException fplException = new FplException(new Date(), ex.getMessage(), request.getDescription(false));
        return new ResponseEntity<>(fplException, ex.getCode());
    }
    
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(
            MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

        FplException fplException = new FplException(new Date(), "Validation Failed", ex.getBindingResult().toString());
        return new ResponseEntity<>(fplException, HttpStatus.BAD_REQUEST);
    }
}


示例测试 运行 1 \(这是预期的结果,我没看错) 输入-

{
    "userName": "A4",
    "userPassword": "randomePass",
    "emailVerificationStatus": "N",
    "fplUserInfo":{
        "age":"19",
        "favouriteTeam":"RealMadrid"
    }
}

预期输出 - 我的回复应该是用户名大小应该大于 5

我的实际输出 -

{
    "timestamp": "2021-05-31T10:23:46.928+00:00",
    "message": "Validation Failed",
    "details": "org.springframework.validation.BeanPropertyBindingResult: 1 errors\nField error in object 'fplUser' on field 'userName': rejected value [A4]; codes [Size.fplUser.userName,Size.userName,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [fplUser.userName,userName];
 arguments []; default message [userName],2147483647,5]; default message [UserName minimum length = 5]"
}

Image - 这是预期的,我得到了我的 Parent 实体的预期响应

示例测试 运行 2 \(这不是预期的结果,我弄错了) 输入-

{
    "userName": "A4truth",
    "userPassword": "randomePass",
    "emailVerificationStatus": "N",
    "fplUserInfo":{
        "age":"16",
        "favouriteTeam":"RealMadrid"
    }
}

预期产出 - 我的回复应该是“年龄至少应年满 18 岁” 并给出 HTTP Bad request 400

我的实际输出 -

{
    "timestamp": "2021-05-31T10:34:30.959+00:00",
    "status": 500,
    "error": "Internal Server Error",
    "trace": "org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction\r\n\tat org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:571)\r\n\tat org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743)\r\n\tat org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711)\r\n\tat org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:654)\r\n\tat org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:407)\r\n\tat org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)\r\n\tat com.sun.proxy.$Proxy237.save(Unknown Source)\r\n\tat com.tester.demojar.services.FplUserService.insertNewUser(FplUserService.java:31)\r\n\tat com.tester.demojar.controller.UserRequestController.insertNewUser(UserRequestController.java:52)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:566)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:652)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:733)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:92)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\r\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:834)\r\nCaused by: javax.persistence.RollbackException: Error while committing the transaction\r\n\tat org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:81)\r\n\tat org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104)\r\n\tat org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:562)\r\n\t... 70 more\r\nCaused by: javax.validation.ConstraintViolationException: Validation failed for classes [com.tester.demojar.entities.FplUserInfo] during persist time for groups [javax.validation.groups.Default, ]\nList of constraint violations:[\n\tConstraintViolationImpl{interpolatedMessage='Age should be minimum 18 Years', propertyPath=age, rootBeanClass=class com.tester.demojar.entities.FplUserInfo, messageTemplate='Age should be minimum 18 Years'}\n]\r\n\tat org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:140)\r\n\tat org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:80)\r\n\tat org.hibernate.action.internal.EntityInsertAction.preInsert(EntityInsertAction.java:214)\r\n\tat org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:100)\r\n\tat org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)\r\n\tat org.hibernate.engine.spi.ActionQueue.lambda$executeActions(ActionQueue.java:478)\r\n\tat java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)\r\n\tat org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)\r\n\tat org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:345)\r\n\tat org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)\r\n\tat org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:93)\r\n\tat org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1362)\r\n\tat org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:453)\r\n\tat org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3212)\r\n\tat org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2380)\r\n\tat org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447)\r\n\tat org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183)\r\n\tat org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access0(JdbcResourceLocalTransactionCoordinatorImpl.java:40)\r\n\tat org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281)\r\n\tat org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)\r\n\t... 71 more\r\n",
    "message": "Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction",
    "path": "/user"
}

图片 - 这不是预期的

图片

感谢任何帮助!!

所以我错过了将 @valid 添加到 属性。 我们应该将 @valid 添加到级联 属性.

private FplUserInfo fplUserInfo;

在 FplUser.java class.

早些时候-

@OneToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.REMOVE}, targetEntity = FplUserInfo.class, fetch = FetchType.LAZY, mappedBy = "fplUser")
    private FplUserInfo fplUserInfo;

更正 -

 @Valid
    @OneToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.REMOVE}, targetEntity = FplUserInfo.class, fetch = FetchType.LAZY, mappedBy = "fplUser")
        private FplUserInfo fplUserInfo;