Spring boot 2.0.2,使用Spring数据如何从实体验证中获取消息

2024-04-22

我正在构建一个 Spring Boot 2.0.2 Web 服务,实体中有许多我不想为空的字段。当尝试保留具有无效字段的实体时,如何从该特定字段获取消息?

例如,我有一个实体;

@Entity
@Table(name="users")
public class User {

    @Column(name="password", columnDefinition = "VARCHAR(250)", nullable = false, length = 250)
    @NotNull(message = "Missing password")
    private String password;
}

我有一个服务类,它尝试创建一个新用户。当它尝试创建一个缺少密码的用户时,会抛出异常;

2018-07-20 17:03:33.195 ERROR 78017 --- [nio-8080-exec-1] o.h.i.ExceptionMapperStandardImpl        : HHH000346: Error during managed flush [Validation failed for classes [com.nomosso.restapi.models.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
    ConstraintViolationImpl{interpolatedMessage='Missing password', propertyPath=password, rootBeanClass=class com.nomosso.restapi.models.User, messageTemplate='Missing password'}
]]
2018-07-20 17:03:33.215 ERROR 78017 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction] with root cause

javax.validation.ConstraintViolationException: Validation failed for classes [com.nomosso.restapi.models.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
    ConstraintViolationImpl{interpolatedMessage='Missing password', propertyPath=password, rootBeanClass=class com.nomosso.restapi.models.User, messageTemplate='Missing password'}
]

我想获取 messageTemplate 的值,以便我可以处理它并在 API 响应中返回它,但我似乎无法捕获异常并获取文本。

目前 API 响应如下所示;

{
    "timestamp": 1532102613231,
    "status": 500,
    "error": "Internal Server Error",
    "message": "Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction",
    "path": "/user"
}

这对于服务的用户来说根本没有多大帮助。我希望得到的答复是这样的;

{
        "timestamp": 1532102613231,
        "status": 400,
        "error": "Bad request",
        "message": "Missing password",
        "path": "/user"
    }

我能够生成自己的错误响应,但为了做到这一点,我需要从无效实体获取消息。

更新: 这是尝试持久化实体的服务;

@Service
public class UserService implements UserDetailsService {

    private UserRepository userRepository;

    private PasswordEncoder passwordEncoder;

    @Autowired
    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }

    /**
     * Creates a new user account
     * @param email email address
     * @param password unencoded password
     * @param firstname firstname
     * @param lastname lastname
     * @param displayName display name
     * @return new User
     */
    public User createUser(String email, String password, String firstname, String lastname, String displayName) {
        User user = new User();
        user.setEmail(email);
        user.setFirstname(firstname);
        user.setLastname(lastname);
        user.setDisplayName(displayName);
        if (password != null && !password.isEmpty()) {
            user.setPassword(passwordEncoder.encode(password));
        }
        user.setEmailVerified(false);
        user.setCreatedAt(new Date());
        user.setUpdatedAt(user.getCreatedAt());

        userRepository.save(user);

        return user;
    }

}

最后,我的用户存储库看起来像这样(spring data);

public interface UserRepository extends CrudRepository<User, String> {
}

验证在执行提交时发生。 因此,听起来您的控制器启动了一个事务,并且提交将在控制器将响应返回给客户端时完成。

所以周边repository.save(...)声明者catch(ConstraintViolationException e)将会毫无用处。
您应该创建一个自定义异常处理程序以允许捕获ConstraintViolationException无论它发生在哪里。
但是你不能直接捕获它,因为 Spring 将它包装成org.springframework.transaction.TransactionSystemException.

事实上准确地说: 1)javax.validation.ConstraintViolationException被 2) 包裹javax.persistence.RollbackException: Error while committing the transaction它本身被 3) 包裹org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction

这是更高级别的异常:



org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
        at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:545)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746)
   ....
  

所以你可以这样写你的ControllerAdvice:

@ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {

    Logger LOGGER = LoggerFactory.getLogger(MyExceptionHandler.class);

    @ExceptionHandler(value = { TransactionSystemException.class })
    protected ResponseEntity<Object> handleConflict(TransactionSystemException ex, WebRequest request) {
        LOGGER.error("Caught", ex);
        Throwable cause = ex.getRootCause();

        if (cause instanceof ConstraintViolationException) {
           Set<ConstraintViolation<?>> constraintViolations = ((ConstraintViolationException) cause).getConstraintViolations();
           // iterate the violations to create your JSON user friendly message
           String msg = ...;
           return handleExceptionInternal(ex, msg , new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
      }
    }        

}

指某东西的用途TransactionSystemException.getRootCause()需要检索原始抛出的异常:即ConstraintViolationException在你的情况下。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring boot 2.0.2,使用Spring数据如何从实体验证中获取消息 的相关文章

随机推荐

  • 设置持续时间格式,如 HH:mm:ss

    有没有一种好方法可以将持续时间格式化为 hh mm ss 之类的格式 而不必处理时区 我试过这个 DateTime durationDate DateTime fromMillisecondsSinceEpoch 0 String dura
  • NET40-RequiresCastle 和 NET40 版本的 Moq 有什么区别?

    在moq的发行版中 有两个版本 NET40 RequiresCastle和NET40 NET40 RequiresCastle 看起来比 NET40 小得多 但在运行时需要 Castle 区别只是因为 Castle 嵌入在 NET40 版本
  • 带有连字符的 ActionLink htmlAttributes

    这有效 a href Url Action class ui btn right Edit a 但这不是 为什么 Html ActionLink Edit edit markets new id 1 new class ui btn rig
  • 在netbeans中使用视觉摆动JPopupmenu

    我想向我的应用程序添加一个弹出菜单 但是当我将它添加到我的面板时 我看到它消失了 我如何像其他菜单一样直观地编辑 jpopup 菜单 我认为您正在谈论在 NetBeans 中使用 matisse 视觉设计器 在这种情况下 该过程与创建只需将
  • 如何使用命名空间从 XML 中“选择”?

    我有一个类似 的 XML 文档
  • setattr 和 getattr 方法

    我有一个锅炉板类 它将一些操作委托给参考类 它看起来像这样 class MyClass def init self someClass self refClass someClass def action1 self self refCla
  • 使用数据库游标有什么好处?

    这是基于我面临的面试问题 非常短的定义可以是 它可用于操作行 由查询返回 除了使用光标之外 列出了点here http msdn microsoft com en us library ms191179 aspx在MSDN上 我心中有一个问
  • Haskell:单词,取消单词分隔符

    有什么办法可以提供分隔符words and unwords在haskell中 使其类似于python中的split和join 另请查看友好的包裹split 它提供了一个模块Data List Split http hackage haske
  • 从 ANT 运行 BAT 文件

    我浏览了论坛上的许多帖子 但无法整理出来 我正在尝试从 ANT 脚本运行 BAT 文件 文件夹层次结构是这样的 Project build xml build C test bat 我编写的 ANT 文件是
  • Railstutorial.org - 未定义的方法“工厂”

    我正在尝试关注 Railstutorial org 目前正在阅读第 7 章 您将在其中开始使用工厂 http railstutorial org chapters modeling and viewing users two sec tes
  • 如何在android中压缩文件夹以制作docx文件?

    我正在尝试制作一个 Android 应用程序 可以打开 docx 文件来读取 编辑和保存它 我的想法是将存档中的所有 xml 文件提取到临时文件夹中 在这个文件夹中我们可以编辑docx的内容 word document xml 问题是当我压
  • java中的for循环和i的值

    在 Horstmann 的 java 教科书 Big Java Late Objects 中 对于 for 循环 例如 for i 0 i lt 5 i 霍斯特曼说 价值观i对于这个 for 循环是0 1 2 3 4 5 然而 在我看来 i
  • Angular UI Bootstrap Popover - 如何添加关闭按钮

    我有一个表格 每个单元格都有一个弹出窗口 如下例所示 对弹出窗口的调用 td td
  • 使用额外模块构建 opencv 错误 ocv_download

    我尝试使用 Extramodules 构建 openCV 如果我尝试使用 cmake 配置项目文件 Windows 10 上的 vc14 x32 则会出现错误 opencv contrib master modules xfeatures2
  • Angular 4显示当前时间

    在 Angular 4 变化检测系统中显示当前时间的正确 规范 方法是什么 问题如下 根据定义 当前时间每时每刻都在不断变化 但 Angular 4 变更检测系统无法检测到它 因此 我认为有必要明确调用ChangeDetectorRef d
  • 如何忽略 Rails 中特定操作的真实性令牌?

    当我不想检查真实性令牌的特定操作时 如何告诉 Rails 跳过检查它 轨道 5 2 您可以使用相同的skip before action https api rubyonrails org classes ActionController
  • C# OpenFileDialog 非模态可能

    是否可以创建 拥有非模式 net OpenFileDialog 我在主对话框中有一个 UI 元素 始终需要可供用户按下 No 打开文件对话框 http msdn microsoft com en us library system wind
  • 领域未获取数据

    我在使用领域时遇到问题 findAll 和 findAllAsync 不会从领域返回任何数据 我正在像这样从主线程更新领域对象 public void updatePhoto final int ticketID realm beginTr
  • 合并多列上的两个 pandas 数据框

    我有两个数据框 gt gt gt df1 Output col1 col2 col3 col4 a abc 10 str1 b abc 20 str2 c def 20 str2 d abc 30 str2 gt gt gt df2 Out
  • Spring boot 2.0.2,使用Spring数据如何从实体验证中获取消息

    我正在构建一个 Spring Boot 2 0 2 Web 服务 实体中有许多我不想为空的字段 当尝试保留具有无效字段的实体时 如何从该特定字段获取消息 例如 我有一个实体 Entity Table name users public cl