如何使Spring Data JPA生成的方法在参数为null时抛出异常

huangapple go评论58阅读模式
英文:

How to make spring data jpa generated methods throw exception on null parameters

问题

Service method:

public User findUserByEmail(String email) {
    try {
        Assert.notNull(email, "email is null!");
        Optional<User> userOptional = userRepo.findUserDAOByEmail(email);
        return userOptional.orElseThrow();
    } 
    catch (...){
        ...
    }
}

Repo:

public interface UserRepo extends JpaRepository<User, Long> {
    Optional<User> findUserByEmail(String email);
}

我有这个调用存储库方法的服务方法,而该方法又是由Spring生成的:

服务方法:

public User findUserByEmail(String email) {
    try {
        Assert.notNull(email, "email为空!");
        Optional<User> userOptional = userRepo.findUserDAOByEmail(email);
        return userOptional.orElseThrow();
    } 
    catch (...){
        ...
    }
}

存储库:

public interface UserRepo extends JpaRepository<User, Long> {
    Optional<User> findUserByEmail(String email);
}

我希望存储库方法像其它方法一样(与Jparepository自带的方法一样)抛出IllegalArgumentException,但实际上它接受了空参数“email”,在数据库中搜索并返回了不存在的用户结果(附注:根据我的模式,email不能为空)。

因此,我执行了Assert.notNull(email, "email为空!");

但我想知道是否有更好的方法来验证“email”不为空?

英文:

I have this service method which calls a repo method which is in turn generated by spring:

Service method:

 public User findUserByEmail(String email) {
        try {
            Assert.notNull(email,&quot;email is null!&quot;);
            Optional&lt;User&gt; userOptional = userRepo.findUserDAOByEmail(email);
            return userOptional.orElseThrow();
        } 
        catch (...){
            ...
        }
    }

Repo:

public interface UserRepo extends JpaRepository&lt;User, Long&gt; {
    Optional&lt;User&gt; findUserByEmail(String email);
}

I wanted the repo method to throw IllegalArgumentException as its friends (the methods that come out of the box with Jparepository do), but instead it accepted the null parameter "email" and searched for it in the database and returned a result that no such user exist (p.s.: email is constrained to be not null in my schema)

So I did Assert.notNull(email,&quot;email is null!&quot;);

But I wonder if there is a better way to validate that "email" is not null?

答案1

得分: 2

以下是翻译好的内容:

一个约束也可以放在参数上,就像这样 -

@Validated
@Repository
public interface UserRepo extends JpaRepository<User, Long> {
    Optional<User> findUserByEmail(@NotNull String email);
}

@Validated 启用 Spring 调用各种验证约束。

工作示例


Gradle 依赖项

    compile 'org.springframework.boot:spring-boot-starter'
    compile 'org.springframework.boot:spring-boot-starter-web'
    compile 'org.springframework.boot:spring-boot-starter-validation'
    compile 'org.springframework.boot:spring-boot-starter-data-jpa'
    compile("mysql:mysql-connector-java:8.0.16")

UserRepository.java

@Validated
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
    Optional<User> findUserByName(@NotEmpty String name);
}

控制台输出

javax.validation.ConstraintViolationException: findUserByName.name: 不能为空
	at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:117) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at com.sun.proxy.$Proxy88.findUserByName(Unknown Source) ~[na:na]
	at com.test.validation.controller.UserController.get(UserController.java:18) ~[main/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
英文:

A constraint can be put on the parameter as well like this -

@Validated
@Repository
public interface UserRepo extends JpaRepository&lt;User, Long&gt; {
    Optional&lt;User&gt; findUserByEmail(@NotNull String email);
}

@Validated enables Spring to invoke various Validation Constraints.

Working Example


gradle dependency

    compile &#39;org.springframework.boot:spring-boot-starter&#39;
    compile &#39;org.springframework.boot:spring-boot-starter-web&#39;
    compile &#39;org.springframework.boot:spring-boot-starter-validation&#39;
    compile &#39;org.springframework.boot:spring-boot-starter-data-jpa&#39;
    compile(&quot;mysql:mysql-connector-java:8.0.16&quot;)

UserRepository.java

@Validated
@Repository
public interface UserRepository extends JpaRepository&lt;User, Integer&gt; {
    Optional&lt;User&gt; findUserByName(@NotEmpty String name);
}

Console Output

javax.validation.ConstraintViolationException: findUserByName.name: must not be empty
	at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:117) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at com.sun.proxy.$Proxy88.findUserByName(Unknown Source) ~[na:na]
	at com.test.validation.controller.UserController.get(UserController.java:18) ~[main/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]

答案2

得分: 0

这些存储库无法直接从服务类访问,因此您需要创建一个带有@Service注解的服务类,然后实现自己的方法来使用UserRepo存储库接口查找用户,然后您可以将该服务类注入到测试单元中并进行自己的测试。

英文:

the repositories has no way to access it directly out of services classes so you need to create a service class annotated with @Service then implement your own method to find the user using the UserRepo repository interface then you can inject the service class into the testing unit and make your own tests.

huangapple
  • 本文由 发表于 2020年10月7日 05:57:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/64234362.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定