Статьи

Обработка проверки формы с помощью Spring 3 MVC

Эта статья является частью серии, посвященной Spring 3. Предыдущими статьями этой серии были Hello World с Spring 3 MVC и Обработка форм с Spring 3 MVC .

Теперь давайте углубимся в Spring. В этой статье мы научимся проверять данные, которые вы получили из форм. Давайте посмотрим на задачу проверки немного более подробно.

Сценарий 1. Нам может потребоваться проверить, например, что предоставленное электронное письмо действительно выглядит как электронное письмо (формат x @ xx упрощен). Это можно сделать, просто запустив некоторые скрипты в самом поле электронной почты. Это должно быть просто. Мы могли бы написать некоторый javascript для запуска в самом браузере. А также написать ту же проверку на стороне сервера [Почему? Читайте здесь . Это верно для всех изолированных проверок, например, проверьте, что данные не равны NULL, проверьте, что данные имеют определенную длину и т. Д. И т. Д.

Сценарий 2 : Жаль, что жизнь не была такой простой Поскольку мы обсуждали проверки электронной почты, допустим, что одна из проверок требует от нас проверки того, что электронная почта относится к определенным доменам (например, организациям-партнерам), чтобы система могла также отправлять определенную конфиденциальную информацию по электронной почте. Допустим, нам нужно проверить, что электронное письмо имеет формат x@partner1.com, x@partner2.com или x@partner3.com. Это может быть тривиально, но это пример типа, в котором проверка не может быть запущена только для данных из самой формы. Каким бы ни был код проверки, ему нужно знать, какие домены являются действительными. И эти данные не присутствовали в данных, предоставленных конечным пользователем в форме. Если вы немного напрягаете воображение, вы можете легко создать сценарий использования, в котором может потребоваться механизм бизнес-правил (например, если правила слишком изменчивы) и / или вы можете добавить элементы интернационализации (например, возраст взрослых не 18 лет во всех странах). ) или другие сложности. Это не изолированные проверки и требуют доступа к дополнительной информации, которая доступна синхронно. Эти проверки могут быть закодированы как на стороне сервера, так и на стороне клиента, хотя было бы справедливо сказать, что он будет опираться больше на стороне сервера.

Сценарий 3 : Опять же, хотелось бы, чтобы жизнь была такой простой. Пока мы находимся на предмет проверки электронных писем, возможно, нам также может понадобиться проверить, является ли электронная почта действительной, то есть это не thisemail@doesnot.exist (я не совсем уверен, что эта электронная почта не существует — или не может существовать в будущее — но вы поняли, я надеюсь). Нам нужно будет отправить электронное письмо на этот идентификатор электронной почты и, возможно, попросить пользователя нажать и подтвердить. Нам нужно асинхронно взаимодействовать с какой-то другой системой через SMTP. Опять же, немного опирайтесь на свое воображение, и ящик всей пандоры раскроется. Вскоре вы интегрируетесь через REST, SOAP, JMS, файловые серверы и решаете вопросы безопасности и аутентификации в распределенных системах. Я бы поспорил, что большинство систем будет проходить проверку на стороне сервера в этой области, и проверка на стороне клиента — хотя технически это возможно — не будет использоваться слишком часто.

Сценарий 4 : И мы еще не затронули тему того, что одни и те же доменные объекты заполняются не только из веб-форм, но также из файлов каналов, сообщений JMS и т. Д. Таким образом, требуется одна и та же логика проверки, применяемая на нескольких каналах. То, что начиналось как маленькая фигура с горсткой невинно выглядящих текстовых полей в начале этого обсуждения , превратилось в монстра.

К счастью, JSR 303 или Bean Validation [ подробнее здесь ] помогут спасти. Это решает Сценарий 1 и 4, упомянутый выше из коробки. И он поможет вам решить сценарии 2 и 3. Я рекомендую вам прочитать раздел, помеченный «Как этот стандарт приносит пользу пользователям? Какие проблемы это решит? по этой ссылке .

Эта спецификация для Java была запрошена в 2006 году, и к концу 2009 года она была выпущена. Другими словами, доступные реализации уже успели повзрослеть за год. Spring 3, будучи гражданином открытого класса первого класса, позволяет вам использовать это стандартное решение, а не изобретать велосипед. И если вам абсолютно необходимо заново изобрести колесо (все профессиональные приложения должны написать, что myAppSpecificKickAssValidator ()) Spring также позволяет это делать. Давайте посмотрим на оба сценария один за другим.

Добавьте поддержку JSR 303 в любой проект на основе Maven

JSR 303 является открытым API. Вы можете найти его по этой ссылке . Любой может реализовать это. Есть реализации hibernate , и Apache Bval, чтобы назвать несколько. Давайте перейдем к реализации Hibernate. Вы можете увидеть их банки в Maven Central по этой ссылке . Последней стабильной версией на момент написания этой статьи является 4.3.0.Final. Вам просто нужно добавить эту зависимость в вашу пом. API также связан с этой реализацией, поэтому вам не нужно добавлять это либо.

Файл: pom.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
<properties>                                                                 
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>       
  [...] 
<hibernate.validation.version>4.3.0.Final</hibernate.validation.version
  [...] 
</properties>                                                           
   
<!-- Hibernate validations --> 
<dependency>                                            
    <groupId>org.hibernate</groupId>                    
    <artifactId>hibernate-validator</artifactId>        
    <version>${hibernate.validation.version}</version>  
</dependency

Просто добавив эту зависимость, вы можете перейти в свой класс сущности / формы и объявить ограничения. JSR 303 имеет несколько стандартных ограничений [ перечисленных здесь ], которые охватывают стандартные проверки, такие как NotNull. Hibernate добавляет еще несколько нестандартных пользовательских ограничений [ перечисленных здесь ]. Они нестандартны, но довольно удобны, например, для проверки действующего адреса электронной почты. Давайте введем обе эти проверки в наш ContactFrm.java. Если вы не знаете, откуда это взялось, вы, скорее всего, не читали предыдущую статью этой серии, то есть « Обработка форм в Spring 3 MVC» .

Файл: /org/academy/ui/spring3/forms/ContactFrm.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
package org.academy.ui.spring3.forms; 
   
import javax.validation.constraints.NotNull; 
   
import org.hibernate.validator.constraints.Email; 
   
public class ContactFrm { 
   
  @NotNull 
  private String firstname; 
  private String lastname; 
  @Email 
  private String email; 
  private String telephone; 
   
  // Getter and setters omitted for brevity.  
  [...] 

Модульный тест

До этого момента у нашего компонента ContactFrm не было никакой функциональности, и, следовательно, я не удосужился провести его модульное тестирование (хотя энтузиасты TDD покачали головой об этом). Однако теперь, просто добавив пару аннотаций, мы добавили функциональность в bean-компонент, и это можно тестировать на модуле (энтузиасты TDD могут порадоваться, начиная прямо сейчас). Давайте добавим модульный тест.

Файл: /src/test/java/org/academy/ui/spring3/forms/ContactFrmTest.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package org.academy.ui.spring3.forms; 
   
import static org.junit.Assert.*; 
   
import java.util.Set; 
   
import javax.validation.ConstraintViolation; 
import javax.validation.Validation; 
import javax.validation.Validator; 
   
import org.junit.BeforeClass; 
import org.junit.Test; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
   
public class ContactFrmTest { 
  private final static Logger logger = LoggerFactory 
      .getLogger(ContactFrmTest.class); 
  private static Validator validator; 
   
  @BeforeClass 
  public static void init() { 
    validator = Validation.buildDefaultValidatorFactory().getValidator(); 
  
   
  @Test 
  public void test() { 
    Set<ConstraintViolation<ContactFrm>> errors; 
    ContactFrm contactFrm = new ContactFrm(); 
   
    errors = validator.validate(contactFrm); 
    printErrors(errors); 
    // We are expecting 1 error here. 
    // Just the NotNull. 
    assertEquals(1, errors.size()); 
    errors.clear(); 
   
    contactFrm.setFirstname("partha"); 
    errors = validator.validate(contactFrm); 
    printErrors(errors); 
    // We are not expecting any errors here. 
    assertEquals(0, errors.size()); 
    errors.clear(); 
   
    contactFrm.setEmail("this can not be a valid email"); 
    errors = validator.validate(contactFrm); 
    printErrors(errors); 
    // We are expecting 1 errors here. 
    assertEquals(1, errors.size()); 
    errors.clear(); 
   
    contactFrm.setEmail("this@mightbevalid.email"); 
    errors = validator.validate(contactFrm); 
    printErrors(errors); 
    // We are not expecting any errors here. 
    assertEquals(0, errors.size()); 
    errors.clear(); 
   
  
     
  // Utility function to print out errors from validation.  
  private void printErrors(Set<ConstraintViolation<ContactFrm>> errors) { 
    if (errors.size() > 0) { 
      for (ConstraintViolation<ContactFrm> error : errors) { 
        logger.debug(error.getMessage()); 
      
    } else
      logger.debug("There were no errors to print."); 
    
  
   

Вы заметите, что мне не нужно использовать какой-либо специальный код Hibernate, Spring или JSR для модульного тестирования. Это просто JUnit. На мой взгляд, тот факт, что я мог бы добавить проверки в POJO, просто добавив пару аннотаций, а затем я мог бы выполнить модульное тестирование с помощью стандартной структуры модульного тестирования без каких-либо настроек, является огромным шагом. И мы только начинаем.

Модульное тестирование — использование возможностей Spring.

Конечно, обнадеживает то, что мы могли бы выполнить полную проверку и модульное тестирование, не полагаясь на Spring. Однако мы бы полностью упустили смысл этого упражнения, если бы не изучали, насколько легко собрать все это вместе с помощью Spring на нашем веб-сайте.

Мы начнем с добавления всех необходимых Spring-зависимостей в наш проект и удаления их из общего журнала, как описано в предыдущей статье .

Файл: /pom.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<dependency>                                          
  <groupId>org.springframework</groupId>            
  <artifactId>spring-context</artifactId>           
  <version>${org.springframework.version}</version
  <exclusions>                                      
    <exclusion>                                   
      <groupId>commons-logging</groupId>        
      <artifactId>commons-logging</artifactId>  
    </exclusion>                                  
  </exclusions>                                     
</dependency>                                         
   
[...] 
   
<dependency>                                          
  <groupId>org.springframework</groupId>            
  <artifactId>spring-test</artifactId>              
  <version>${org.springframework.version}</version
  <scope>test</scope>                               
  <exclusions>                                      
    <exclusion>                                   
      <groupId>commons-logging</groupId>        
      <artifactId>commons-logging</artifactId>  
    </exclusion>                                  
  </exclusions>                                     
</dependency>      

Теперь добавьте магию @RunWith и @ContextConfiguration в модульный тест, как описано в предыдущей статье .

Файл: /src/test/java/org/academy/ui/spring3/forms/ContactFrmTest.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
@RunWith(SpringJUnit4ClassRunner.class
@ContextConfiguration 
public class ContactFrmTest { 
  private final static Logger logger = LoggerFactory 
      .getLogger(ContactFrmTest.class); 
   
  @Autowired 
  private Validator validator; 
   
  // This is no more required as Spring does it for us.  
  // @BeforeClass 
  // public static void init() { 
  // validator = Validation.buildDefaultValidatorFactory().getValidator(); 
  // } 

[Остальной код пропущен, так как он остается тем же.]

Теперь все, что нам остается, это сказать Spring, что он должен Autowire в валидаторе. Это мы делаем, используя конфигурацию, а не код.

Файл: /src/test/resources/org/academy/ui/spring3/forms/ContactFrmTest-context.xml

01
02
03
04
05
06
07
08
09
10
11
12
<?xml version="1.0" encoding="UTF-8"?> 
   
  <bean id="validator" 
    class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" /> 
</beans

Там все готово. Теперь вы можете использовать «mvn -e clean install» для запуска всего этого кода и его модульного тестирования. Если вы чувствуете себя слишком требовательно, вы можете использовать «mvn -e site», чтобы создать хороший HTML-сайт, который будет сообщать о покрытии кода.

Подробнее:

Ссылка: обработка проверки формы с помощью Spring 3 MVC от нашего партнера JCG Partho в блоге Tech for Enterprise