Guia: Thymeleaf + Spring. Parte 1

Documentação original

Segunda parte
Terceira parte

Sumário:

1. Integração do timelo com o Spring
2. Dialeto SpringStandard
3. Exibições e exibições de resolvedores
3.1 Exibições e exibições de resolvedores no Spring MVC
3.2 Exibições e exibições de resolvedores no Thymeleaf
4. Gerente de iniciação de sementes de tomilho de primavera
4.1 Conceito
4.2 Camada de negócios
4.3 Configuração do Spring MVC
4.4 Controlador
4.5 Configurando o serviço de conversão
5 Exibir dados iniciais de sementes
6 Criando formulários
6.1 Processando um objeto de comando
6.2 Entradas
6.3 Campos da caixa de seleção
6.4 Campos dos botões de opção
6.5 Seletores suspensos / lista
6.6 Campos dinâmicos
7 Mensagens de verificação e erro
7.1 Erros de campo
7.2 Todos os erros
7.3 Erros globais
7.4 Exibindo erros fora dos formulários
7.5 Objetos de erro avançados
8 Este ainda é um protótipo!
9 O serviço de conversão
9.1 Configuração
9.2 Sintaxe de colchetes duplos
9.3 Uso em formulários
9.4 #conversions objeto de conversão
10 Fragmentos de renderização do modelo Fragmentos de modelo (AJAX etc)
10.1 Definindo fragmentos em um bean de exibição
10.2 Definindo fragmentos no valor de retorno do controlador
11 Recursos avançados de integração
11.1 Integração com RequestDataValueProcessor
11.1 Criando URIs para controladores
12 Integração do Spring WebFlow
12.2 Snippets AJAX no Spring WebFlow

Este guia explica como o Thymeleaf pode ser integrado ao Spring Framework, especialmente (mas não apenas) o Spring MVC.

Observe que o Thymeleaf possui integrações para as versões 3.xe 4.x do Spring Framework e superior, fornecidas por duas bibliotecas separadas chamadas thymeleaf-spring3 e thymeleaf-spring4. Essas bibliotecas são empacotadas em arquivos .jar separados (thymeleaf-spring3- {version} .jar e thymeleaf-spring4- {version} .jar) e devem ser adicionadas ao caminho da sua classe para usar as integrações do Thymeleaf Spring em seu aplicativo.

As amostras de código e aplicativos de amostra neste guia usam o Spring 4.xe suas integrações Thymeleaf correspondentes, mas o conteúdo deste texto também se aplica ao Spring 3.x. Se seu aplicativo usa o Spring 3.x, tudo o que você precisa fazer é substituir o pacote org.thymeleaf.spring4 por org.thymeleaf.spring3 nos exemplos de código.

1. Integração do timelo com o Spring


O Thymeleaf oferece um conjunto de integrações do Spring que permitem que ele seja usado como uma substituição JSP com todos os recursos nos aplicativos Spring MVC.

Essas integrações permitem:

  1. Faça um mapeamento para os métodos nos objetos do Spring MVC Controller de padrões gerenciados pelo Thymeleaf, assim como o JSP.
  2. Use Spring Expression Language (Spring EL) em vez de OGNL em seus modelos.
  3. Crie formulários em seus modelos totalmente integrados aos componentes e beans de suporte a seu formulário, incluindo o uso de editores de propriedades, serviços de conversão e tratamento de erros de validação.
  4. Exibir mensagens de internacionalização de arquivos de mensagens gerenciados pelo Spring (por meio de objetos regulares MessageSource).
  5. Encontre seus padrões usando mecanismos nativos de resolução de recursos do Spring.

Observe que, para entender completamente este tutorial, você deve primeiro passar pelo tutorial " Usando o Thymeleaf ", que explica o dialeto padrão em detalhes.

2. Dialeto SpringStandard


Para obter uma integração mais fácil e melhor, o Thymeleaf fornece um dialeto que implementa especificamente todas as funções necessárias para trabalhar corretamente com o Spring.

Esse dialeto específico é baseado no dialeto Thymeleaf padrão e é implementado na classe org.thymeleaf.spring4.dialect.SpringStandardDialect, que na verdade deriva de org.thymeleaf.standard.StandardDialect.

Além de todas as funções já presentes no dialeto padrão e, portanto, herdadas, o SpringStandard Dialect oferece as seguintes funções específicas:

  1. Usando Spring Expression Language (Spring EL ou SpEL) como uma linguagem de expressão variável, não OGNL. Portanto, todas as expressões $ {...} e * {...} serão avaliadas pelo mecanismo da linguagem de expressões Spring. Observe também que o suporte ao compilador Spring EL (Spring 4.2.4+) está disponível.
  2. Acesse qualquer componente no contexto do seu aplicativo usando a sintaxe SpringEL: $ {@ myBean.doSomething ()}
  3. Novos atributos para processar o formulário: th: field , th: errors e th: errorclass , exceto para a nova implementação do th: object , que permite usá-lo para selecionar o comando do formulário.
  4. O método de objeto e expressão é # themes.code (...) , que é equivalente à tag customizada JSP spring: theme .
  5. O método de objeto e expressão, # mvc.uri (...) , que é equivalente à função customizada JSP spring: mvcUrl (...) (apenas no Spring 4.1+).

Observe que, na maioria dos casos, você não deve usar esse dialeto diretamente em um objeto TemplateEngine regular como parte de sua configuração. Se você não tiver necessidades especiais de integração com o Spring, crie uma instância de uma nova classe de modelo que execute automaticamente todas as etapas de configuração necessárias: org.thymeleaf.spring4.SpringTemplateEngine .

Exemplo de configuração do bean:

@Bean public SpringResourceTemplateResolver templateResolver(){ // SpringResourceTemplateResolver automatically integrates with Spring's own // resource resolution infrastructure, which is highly recommended. SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); templateResolver.setApplicationContext(this.applicationContext); templateResolver.setPrefix("/WEB-INF/templates/"); templateResolver.setSuffix(".html"); // HTML is the default value, added here for the sake of clarity. templateResolver.setTemplateMode(TemplateMode.HTML); // Template cache is true by default. Set to false if you want // templates to be automatically updated when modified. templateResolver.setCacheable(true); return templateResolver; } @Bean public SpringTemplateEngine templateEngine(){ // SpringTemplateEngine automatically applies SpringStandardDialect and // enables Spring's own MessageSource message resolution mechanisms. SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver()); // Enabling the SpringEL compiler with Spring 4.2.4 or newer can // speed up execution in most scenarios, but might be incompatible // with specific cases when expressions in one template are reused // across different data types, so this flag is "false" by default // for safer backwards compatibility. templateEngine.setEnableSpringELCompiler(true); return templateEngine; } 

Ou usando a configuração Spring baseada em XML:

 <!-- SpringResourceTemplateResolver automatically integrates with Spring's own --> <!-- resource resolution infrastructure, which is highly recommended. --> <bean id="templateResolver" class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver"> <property name="prefix" value="/WEB-INF/templates/" /> <property name="suffix" value=".html" /> <!-- HTML is the default value, added here for the sake of clarity. --> <property name="templateMode" value="HTML" /> <!-- Template cache is true by default. Set to false if you want --> <!-- templates to be automatically updated when modified. --> <property name="cacheable" value="true" /> </bean> <!-- SpringTemplateEngine automatically applies SpringStandardDialect and --> <!-- enables Spring's own MessageSource message resolution mechanisms. --> <bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine"> <property name="templateResolver" ref="templateResolver" /> <!-- Enabling the SpringEL compiler with Spring 4.2.4 or newer can speed up --> <!-- execution in most scenarios, but might be incompatible with specific --> <!-- cases when expressions in one template are reused across different data --> <!-- ypes, so this flag is "false" by default for safer backwards --> <!-- compatibility. --> <property name="enableSpringELCompiler" value="true" /> </bean> 

3. Exibições e exibições de resolvedores


3.1 Exibições e exibições de resolvedores no Spring MVC



O Spring MVC possui duas interfaces que correspondem ao núcleo do seu sistema de modelos:

  • org.springframework.web.servlet.View
  • org.springframework.web.servlet.ViewResolver

Visualiza as páginas de modelo em nossos aplicativos e permite alterar e predeterminar o comportamento delas, definindo-as como componentes do bean. As visualizações são responsáveis ​​por renderizar a interface HTML real, como regra, pela execução de algum tipo de mecanismo de modelo, por exemplo, Thymeleaf.

ViewResolvers são objetos responsáveis ​​pela obtenção de objetos View para uma operação e localidade específicas. Normalmente, os controladores solicitam ao ViewResolvers que encaminhe a visualização com um nome específico (a sequência retornada pelo método do controlador) e, em seguida, todos os meios de resolver a visualização no aplicativo são executados em uma cadeia ordenada até que um deles possa resolver essa visualização. Nesse caso, o objeto View é retornado e o controle é transferido para ele para renderizar HTML.

Observe que nem todas as páginas em nossos aplicativos devem ser definidas como visualizações, mas apenas aquelas cujo comportamento queremos que não seja padrão ou personalizado de uma maneira especial (por exemplo, conectando alguns componentes especiais). Se um ViewResolver for solicitado para uma visualização que não possua um bean correspondente (que é um caso comum), uma nova Visualização será criada ad hoc e retornada.

Uma configuração típica JSP + JSTL ViewResolver em um aplicativo Spring MVC do passado era assim:

 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/jsps/" /> <property name="suffix" value=".jsp" /> <property name="order" value="2" /> <property name="viewNames" value="*jsp" /> </bean> 

Uma rápida olhada em suas propriedades é suficiente para descobrir como foi configurado:

  1. viewClass define a classe de instâncias de exibição. Isso é necessário para o reconhecedor JSP, mas não quando estamos trabalhando com o Thymeleaf.
  2. O prefixo e o sufixo funcionam de maneira semelhante aos atributos com o mesmo nome nos objetos Thymeleaf TemplateResolver.
  3. order define a ordem em que o ViewResolver será solicitado na cadeia.
  4. O viewNames permite definir (com caracteres curinga) os nomes das visualizações que este ViewResolver resolverá.

3.2 Exibições e exibições de resolvedores no Thymeleaf


O Thymeleaf oferece implementações para as duas interfaces mencionadas acima:

  1. org.thymeleaf.spring4.view.ThymeleafView
  2. org.thymeleaf.spring4.view.ThymeleafViewResolver

Essas duas classes serão responsáveis ​​pelo tratamento de modelos Thymeleaf como resultado da execução dos controladores.

A configuração da Resolver Thymeleaf View é muito semelhante ao JSP:

 @Bean public ThymeleafViewResolver viewResolver(){ ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setTemplateEngine(templateEngine()); // NOTE 'order' and 'viewNames' are optional viewResolver.setOrder(1); viewResolver.setViewNames(new String[] {".html", ".xhtml"}); return viewResolver; } 

... ou em XML:

 <bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver"> <property name="templateEngine" ref="templateEngine" /> <!-- NOTE 'order' and 'viewNames' are optional --> <property name="order" value="1" /> <property name="viewNames" value="*.html,*.xhtml" /> </bean> 

O parâmetro templateEngine , é claro, é o objeto SpringTemplateEngine que definimos no capítulo anterior. Os outros dois ( order e viewNames ) são opcionais e têm o mesmo significado que no JSP ViewResolver, que vimos anteriormente.

Observe que não precisamos de parâmetros de prefixo ou sufixo, porque eles já estão especificados no resolvedor de modelos (que, por sua vez, são passados ​​para o mecanismo de modelos).

Mas e se quisermos definir um bean View e adicionar algumas variáveis ​​estáticas ? Fácil, basta definir um protótipo para ele:

 @Bean @Scope("prototype") public ThymeleafView mainView() { ThymeleafView view = new ThymeleafView("main"); // templateName = 'main' view.setStaticVariables( Collections.singletonMap("footer", "The ACME Fruit Company")); return view; } 

Feito isso, você pode solicitar esse componente selecionando-o pelo nome (neste caso, mainView).

4. Gerente de iniciação de sementes de tomilho de primavera


O código fonte dos exemplos mostrados neste e nos capítulos subseqüentes deste guia pode ser encontrado no repositório do GitHub Spring Seyme Seed Starter Manager .

4.1 Conceito


Em relação ao Thymeleaf, somos grandes fãs de tomilho, e a cada primavera preparamos nossos kits iniciais com bom solo e nossas sementes favoritas, plantamos sob o sol espanhol e esperamos pacientemente que nossas novas plantas cresçam.

Mas este ano, estávamos cansados ​​de colar etiquetas nos contêineres iniciais para descobrir o que havia em cada célula do contêiner, por isso decidimos preparar o aplicativo usando o Spring MVC e o Thymeleaf para nos ajudar a catalogar nossos iniciantes: Spring Thyme SeedStarter Manager .



Semelhante ao aplicativo Good Thymes Virtual Grocery, desenvolvido no tutorial Usando o Thymeleaf, o STSM nos permite demonstrar os aspectos mais importantes da integração do Thymeleaf como um mecanismo de modelo para o Spring MVC.

4.2 Camada de negócios


Vamos precisar de uma camada de negócios muito simples para nosso aplicativo. Primeiro de tudo, vamos olhar para nossos objetos de modelo:

imagem

Algumas classes de serviço muito simples fornecerão os métodos de negócios necessários. Como:

 @Service public class SeedStarterService { @Autowired private SeedStarterRepository seedstarterRepository; public List<SeedStarter> findAll() { return this.seedstarterRepository.findAll(); } public void add(final SeedStarter seedStarter) { this.seedstarterRepository.add(seedStarter); } } 

E:

 @Service public class VarietyService { @Autowired private VarietyRepository varietyRepository; public List<Variety> findAll() { return this.varietyRepository.findAll(); } public Variety findById(final Integer id) { return this.varietyRepository.findById(id); } } 

4.3 Configuração do Spring MVC


Em seguida, precisamos definir a configuração do Spring MVC para o aplicativo, que incluirá não apenas artefatos padrão do Spring MVC, como processamento de recursos ou varredura de anotações, mas também instanciação do Template Engine e do View Resolver .

 @Configuration @EnableWebMvc @ComponentScan public class SpringWebConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware { private ApplicationContext applicationContext; public SpringWebConfig() { super(); } public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } /* ******************************************************************* */ /* GENERAL CONFIGURATION ARTIFACTS */ /* Static Resources, i18n Messages, Formatters (Conversion Service) */ /* ******************************************************************* */ @Override public void addResourceHandlers(final ResourceHandlerRegistry registry) { super.addResourceHandlers(registry); registry.addResourceHandler("/images/**").addResourceLocations("/images/"); registry.addResourceHandler("/css/**").addResourceLocations("/css/"); registry.addResourceHandler("/js/**").addResourceLocations("/js/"); } @Bean public ResourceBundleMessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("Messages"); return messageSource; } @Override public void addFormatters(final FormatterRegistry registry) { super.addFormatters(registry); registry.addFormatter(varietyFormatter()); registry.addFormatter(dateFormatter()); } @Bean public VarietyFormatter varietyFormatter() { return new VarietyFormatter(); } @Bean public DateFormatter dateFormatter() { return new DateFormatter(); } /* **************************************************************** */ /* THYMELEAF-SPECIFIC ARTIFACTS */ /* TemplateResolver <- TemplateEngine <- ViewResolver */ /* **************************************************************** */ @Bean public SpringResourceTemplateResolver templateResolver(){ // SpringResourceTemplateResolver automatically integrates with Spring's own // resource resolution infrastructure, which is highly recommended. SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); templateResolver.setApplicationContext(this.applicationContext); templateResolver.setPrefix("/WEB-INF/templates/"); templateResolver.setSuffix(".html"); // HTML is the default value, added here for the sake of clarity. templateResolver.setTemplateMode(TemplateMode.HTML); // Template cache is true by default. Set to false if you want // templates to be automatically updated when modified. templateResolver.setCacheable(true); return templateResolver; } @Bean public SpringTemplateEngine templateEngine(){ // SpringTemplateEngine automatically applies SpringStandardDialect and // enables Spring's own MessageSource message resolution mechanisms. SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver()); // Enabling the SpringEL compiler with Spring 4.2.4 or newer can // speed up execution in most scenarios, but might be incompatible // with specific cases when expressions in one template are reused // across different data types, so this flag is "false" by default // for safer backwards compatibility. templateEngine.setEnableSpringELCompiler(true); return templateEngine; } @Bean public ThymeleafViewResolver viewResolver(){ ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setTemplateEngine(templateEngine()); return viewResolver; } } 

4.4 Controlador


Obviamente, também precisamos de um controlador para nossa aplicação. Como o STSM conterá apenas uma página da web com uma lista de valores iniciais e um formulário para adicionar novos, escreveremos apenas uma classe de controlador para todas as interações do servidor:

 @Controller public class SeedStarterMngController { @Autowired private VarietyService varietyService; @Autowired private SeedStarterService seedStarterService; ... } 

Agora vamos ver o que podemos adicionar a essa classe de controlador.

Atributos do modelo

Primeiro, adicionaremos alguns atributos de modelo que precisaremos na página:

 @ModelAttribute("allTypes") public List<Type> populateTypes() { return Arrays.asList(Type.ALL); } @ModelAttribute("allFeatures") public List<Feature> populateFeatures() { return Arrays.asList(Feature.ALL); } @ModelAttribute("allVarieties") public List<Variety> populateVarieties() { return this.varietyService.findAll(); } @ModelAttribute("allSeedStarters") public List<SeedStarter> populateSeedStarters() { return this.seedStarterService.findAll(); } 

Métodos mapeados

E agora a parte mais importante do controlador, os métodos mapeados: um para exibir a página do formulário e o outro para lidar com a adição de novos objetos SeedStarter .

 @RequestMapping({"/","/seedstartermng"}) public String showSeedstarters(final SeedStarter seedStarter) { seedStarter.setDatePlanted(Calendar.getInstance().getTime()); return "seedstartermng"; } @RequestMapping(value="/seedstartermng", params={"save"}) public String saveSeedstarter( final SeedStarter seedStarter, final BindingResult bindingResult, final ModelMap model) { if (bindingResult.hasErrors()) { return "seedstartermng"; } this.seedStarterService.add(seedStarter); model.clear(); return "redirect:/seedstartermng"; } 

4.5 Configurando o serviço de conversão


Para fornecer formatação simples para objetos Date e objetos Variety em nossa camada de visualização, configuramos nosso aplicativo para que o objeto Spring ConversionService fosse criado e inicializado ( WebMvcConfigurerAdapter extensível) usando alguns dos objetos de formatação necessários.
Olhe novamente:

 @Override public void addFormatters(final FormatterRegistry registry) { super.addFormatters(registry); registry.addFormatter(varietyFormatter()); registry.addFormatter(dateFormatter()); } @Bean public VarietyFormatter varietyFormatter() { return new VarietyFormatter(); } @Bean public DateFormatter dateFormatter() { return new DateFormatter(); } 

Os formatadores Spring são implementações da interface org.springframework.format.Formatter . Para obter mais informações sobre como a infraestrutura de conversão do Spring funciona, consulte os documentos em spring.io .

Vejamos um DateFormatter que formata datas de acordo com a string de formato presente na chave date.format do nosso Messages.properties :

 public class DateFormatter implements Formatter<Date> { @Autowired private MessageSource messageSource; public DateFormatter() { super(); } public Date parse(final String text, final Locale locale) throws ParseException { final SimpleDateFormat dateFormat = createDateFormat(locale); return dateFormat.parse(text); } public String print(final Date object, final Locale locale) { final SimpleDateFormat dateFormat = createDateFormat(locale); return dateFormat.format(object); } private SimpleDateFormat createDateFormat(final Locale locale) { final String format = this.messageSource.getMessage("date.format", null, locale); final SimpleDateFormat dateFormat = new SimpleDateFormat(format); dateFormat.setLenient(false); return dateFormat; } } 

VarietyFormatter converte automaticamente entre nossos objetos Variety e a maneira como queremos usá-los em nossos formulários (principalmente pelos valores de seus campos de identificação ):

 public class VarietyFormatter implements Formatter<Variety> { @Autowired private VarietyService varietyService; public VarietyFormatter() { super(); } public Variety parse(final String text, final Locale locale) throws ParseException { final Integer varietyId = Integer.valueOf(text); return this.varietyService.findById(varietyId); } public String print(final Variety object, final Locale locale) { return (object != null ? object.getId().toString() : ""); } } 

Aprenderemos mais sobre como essas ferramentas de formatação afetam a maneira como exibimos nossos dados no futuro.

Source: https://habr.com/ru/post/pt435062/


All Articles