mvc example java validation spring-mvc hibernate-validator

java - spring mvc hibernate crud example eclipse



Spring MVC+Hibernate: estrategias de validaciĆ³n de datos (1)

Todos sabemos, que Spring MVC se integra bien con Hibernate Validator y JSR-303 en general. Pero Hibernate Validator, como alguien dijo, es algo solo para Bean Validation, lo que significa que se deben enviar validaciones más complejas a la capa de datos. Ejemplos de tales validaciones: la singularidad de las claves de negocios, la dependencia dentro de los registros (que generalmente es algo que apunta a problemas de diseño de DB, pero todos vivimos en un mundo imperfecto). Incluso las validaciones simples como la longitud del campo de cadena pueden ser controladas por algún valor de DB, lo que hace que el Validador de Hibernate sea inutilizable.

Entonces, mi pregunta es, ¿hay algo que Spring o Hibernate o JSR ofrezca para realizar validaciones tan complejas? ¿Existe algún patrón o pieza tecnológica establecida para realizar dicha validación en una configuración estándar de Repositorio-Servicio-Controlador basada en Spring e Hibernate?

ACTUALIZACIÓN: Déjame ser más específico. Por ejemplo, hay un formulario que envía una solicitud de guardar AJAX al método de save del controlador. Si se produce algún error de validación, ya sea simple o "complejo", deberíamos volver al navegador con algún json que indique un campo problemático y un error asociado. Para errores simples, puedo extraer el campo (si corresponde) y el mensaje de error de BindingResult . ¿Qué infraestructura (tal vez específica, no excepciones ad hoc?) Propondría para errores "complejos"? El uso del controlador de excepciones no me parece una buena idea, ya que separar un solo proceso de validación entre el método de save y @ExceptionHandler hace que las cosas se @ExceptionHandler . Actualmente utilizo alguna excepción ad-hoc (como, ValidationException ):

public @ResponseBody Result save(@Valid Entity entity, BindingResult errors) { Result r = new Result(); if (errors.hasErrors()) { r.setStatus(Result.VALIDATION_ERROR); // ... } else { try { dao.save(entity); r.setStatus(Result.SUCCESS); } except (ValidationException e) { r.setStatus(Result.VALIDATION_ERROR); r.setText(e.getMessage()); } } return r; }

¿Puedes ofrecer un enfoque más óptimo?


Sí, hay un buen patrón antiguo de Java de lanzar Excepciones .
Spring MVC lo integra bastante bien (para ejemplos de código, puedes saltar directamente a la segunda parte de mi respuesta).

Lo que usted llama "validaciones complejas" son, de hecho, excepciones: error de unicidad de clave de negocio, errores de capa baja o DB, etc.

Recordatorio: ¿Qué es la validación en Spring MVC?

La validación debe ocurrir en la capa de presentación. Básicamente se trata de validar los campos del formulario enviado.

Podríamos clasificarlos en dos tipos:

1) Validación de luz (con JSR-303 / validación de hibernación): verificar que un campo enviado tenga un @Size / @Length dado, que sea @NotNull o @NotEmpty / @NotBlank , verificar que tenga un formato de @Email electrónico, etc. .

2) La validación pesada o la validación compleja se refieren más a casos particulares de validaciones de campo, como la validación de campo cruzado:

  • Ejemplo 1: El formulario tiene fieldA , fieldB y fieldC . Individualmente, cada campo puede estar vacío, pero al menos uno de ellos no debe estar vacío.
  • Ejemplo 2: si el campo userAge tiene un valor menor de 18, el campo responsibleUser userAge no debe ser nulo y la edad del responsibleUser userAge debe ser mayor de 21 años.

Estas validaciones se pueden implementar con implementaciones de Spring Validator o anotaciones / restricciones personalizadas .

Ahora entiendo que con todas estas facilidades de validación, además del hecho de que Spring no es intrusivo en absoluto y le permite hacer lo que quiera (para bien o para mal), uno puede tener la tentación de usar el "martillo de validación" para cualquier cosa vagamente relacionada. al manejo de errores.
Y funcionaría: solo con la validación, usted verifica todos los problemas posibles en sus validadores / anotaciones (y casi no lanza ninguna excepción en las capas inferiores). Es malo, porque rezas para que pienses en todos los casos. No aprovecha las excepciones de Java que le permitirían simplificar su lógica y reducir la posibilidad de cometer un error olvidando verificar que algo haya tenido un error.

Por lo tanto, en el mundo de Spring MVC, no se debe confundir la validación (es decir, la validación de la interfaz de usuario ) con las excepciones de capa inferior, como las excepciones de servicio o las excepciones de DB (unicidad de clave, etc.).

¿Cómo manejar las excepciones en Spring MVC de una manera práctica?

Algunas personas piensan "Oh, Dios mío, así que en mi controlador tendría que revisar todas las posibles excepciones verificadas una por una, y pensar en un mensaje de error para cada una de ellas. ¡NO HAY MANERA!". Yo soy una de esas personas. :-)

Para la mayoría de los casos, solo use alguna clase de excepción verificada genérica que extenderían todas sus excepciones. Luego simplemente manéjelo en su controlador Spring MVC con @ExceptionHandler y un mensaje de error genérico.

Ejemplo de código:

public class MyAppTechnicalException extends Exception { ... }

y

@Controller public class MyController { ... @RequestMapping(...) public void createMyObject(...) throws MyAppTechnicalException { ... someServiceThanCanThrowMyAppTechnicalException.create(...); ... } ... @ExceptionHandler(MyAppTechnicalException.class) public String handleMyAppTechnicalException(MyAppTechnicalException e, Model model) { // Compute your generic error message/code with e. // Or just use a generic error/code, in which case you can remove e from the parameters String genericErrorMessage = "Some technical exception has occured blah blah blah" ; // There are many other ways to pass an error to the view, but you get the idea model.addAttribute("myErrors", genericErrorMessage); return "myView"; } }

Sencillo, rápido, fácil y limpio!

Para aquellos momentos en que necesita mostrar mensajes de error para algunas excepciones específicas, o cuando no puede tener una excepción genérica de nivel superior debido a un sistema heredado mal diseñado que no puede modificar, simplemente agregue otras @ExceptionHandler s.
Otro truco: para un código menos saturado, puede procesar múltiples excepciones con

@ExceptionHandler({MyException1.class, MyException2.class, ...}) public String yourMethod(Exception e, Model model) { ... }

En pocas palabras: ¿cuándo usar la validación? ¿Cuándo usar excepciones?

  • Errores de la UI = validación = facilidades de validación (anotaciones JSR-303, anotaciones personalizadas, validador Spring)
  • Errores de capas inferiores = excepciones

Cuando digo "Errores de la interfaz de usuario", me refiero a que "el usuario ingresó algo incorrecto en su forma".

Referencias: