Избранное сообщение

Фетісов В. С. Комп’ютерні технології в тестуванні. Навчально-методичний посібник. 2-ге видання, перероблене та доповнене / Мои публикации

В 10-х годах я принимал участие в программе Европейского Союза Tempus "Освітні вимірювання, адаптовані до стандартів ЄС". В рамк...

Благодаря Интернету количество писателей и поэтов увеличивается в геометрической прогрессии. Поголовье читателей начинает заметно отставать.

суббота, 5 января 2019 г.

Руководство: Thymeleaf + Spring. Часть 1 / Программирование на Java

Оригинал документации 

05.01.18. В этом руководстве объясняется, как Thymeleaf может быть интегрирован с Spring Framework, особенно (но не только) Spring MVC.

Обратите внимание, что Thymeleaf имеет интеграции для версий 3.x и 4.x Spring Framework и выше, предоставляемые двумя отдельными библиотеками, которые называются thymeleaf-spring3 и thymeleaf-spring4. Эти библиотеки упакованы в отдельные файлы .jar (thymeleaf-spring3-{version}.jar и thymeleaf-spring4-{version}.jar) и должны быть добавлены в ваш путь к классам для использования интеграций Thymeleaf Spring в вашем приложении.

Примеры кода и пример приложения в этом руководстве используют Spring 4.x и соответствующие ему интеграции Thymeleaf, но содержимое этого текста также применимо для Spring 3.x. Если ваше приложение использует Spring 3.x, все, что вам нужно сделать, это заменить пакет org.thymeleaf.spring4 на org.thymeleaf.spring3 в примерах кода.

1. Интеграция Thymeleaf с Spring

Thymeleaf предлагает набор интеграций Spring, которые позволяют использовать его как полнофункциональную замену JSP в приложениях Spring MVC.

Эти интеграции позволят вам:

  1. Сделать сопоставление методам в ваших объектах Spring MVC Controller шаблонов, управляемых Thymeleaf, точно так же, как вы делаете это с JSP.
  2. Использовать Spring Expression Language (Spring EL) вместо OGNL в ваших шаблонах.
  3. Создавать формы в своих шаблонах, которые полностью интегрированы с вашими компонентами (bean) поддержки форм и привязками результатов, включая использование редакторов свойств, служб преобразования и обработки ошибок проверки.
  4. Отображать сообщения интернационализации из файлов сообщений, управляемых Spring (через обычные объекты MessageSource).
  5. Находить ваши шаблоны, используя собственные механизмы разрешения ресурсов Spring.
Обратите внимание, что для того, чтобы полностью понять этот учебник, вы должны сначала пройти учебник «Использование Thymeleaf», который подробно объясняет стандартный диалект.

2. SpringStandard Диалект

Чтобы добиться более легкой и лучшей интеграции, Thymeleaf предоставляет диалект, который специально реализует все необходимые функции для правильной работы с Spring.

Этот конкретный диалект основан на стандартном диалекте Thymeleaf и реализован в классе org.thymeleaf.spring4.dialect.SpringStandardDialect, который фактически происходит от org.thymeleaf.standard.StandardDialect.

Помимо всех функций, уже присутствующих в стандартном диалекте и, следовательно, унаследованных, SpringStandard Dialect предлагает следующие специфические функции:

  1. Использование язык выражений Spring (Spring EL или SpEL) в качестве языка выражений переменных, а не OGNL. Следовательно, все выражения ${...} и *{...} будут оцениваться движком языка выражений Spring. Также обратите внимание, что доступна поддержка компилятора Spring EL (Spring 4.2.4+).
  2. Доступ к любым компонентам в контексте вашего приложения с использованием синтаксиса SpringEL: ${@myBean.doSomething()}
  3. Новые атрибуты для обработки формы: th:fieldth:errors и th:errorclass, кроме новой реализации th:object, которая позволяет использовать ее для выбора команды формы.
  4. Объект и метод выражения #themes.code(...), который эквивалентен пользовательскому тегу JSP spring:theme.
  5. Объект и метод выражения, #mvc.uri(...), который эквивалентен пользовательской функции JSP spring:mvcUrl(...) (только в Spring 4.1+).
Обратите внимание, что в большинстве случаев вам не следует использовать этот диалект непосредственно в обычном объекте TemplateEngine как части его конфигурации. Если у вас нет особых потребностей в интеграции с Spring, вам следует вместо этого создавать экземпляр нового класса шаблонизатора, который автоматически выполняет все необходимые шаги конфигурации: org.thymeleaf.spring4.SpringTemplateEngine.

Пример конфигурации бина:

@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;
}

Или, используя конфигурацию Spring на основе 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. Views и View Resolvers



3.1 Views и View Resolvers в Spring MVC


В Spring MVC есть два интерфейса, которые соответствуют ядру его системы шаблонов:

  • org.springframework.web.servlet.View
  • org.springframework.web.servlet.ViewResolver
Views моделируют страницы в наших приложениях и позволяют изменять и предопределять их поведение, определяя их как bean-компоненты. Представления (Views) отвечают за рендеринг реального HTML-интерфейса, как правило, за выполнение какого-либо механизма шаблонов, например Thymeleaf.

ViewResolvers — это объекты, отвечающие за получение объектов View для конкретной операции и локали. Обычно контроллеры просят ViewResolvers переслать представление с определенным именем (строка, возвращаемая методом контроллера), а затем все средства разрешения представления в приложении выполняются в упорядоченной цепочке, пока один из них не сможет разрешить это представление, в каком случае объект View возвращается и ему передается управление для рендеризации HTML.

Обратите внимание, что не все страницы в наших приложениях должны быть определены как представления, а только те, поведение которых мы хотим, чтобы мы были нестандартными или настраивались особым образом (например, путем подключения к нему некоторых специальных компонентов). Если ViewResolver запрашивается представление, у которого нет соответствующего bean-компонента (что является распространенным случаем), новый объект View создается ad hoc и возвращается.

Типичная конфигурация JSP + JSTL ViewResolver в приложении Spring MVC из прошлого выглядела так:

<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>

Беглого взгляда на его свойства достаточно, чтобы узнать, как он был настроен:

  1. viewClass устанавливает класс экземпляров View. Это необходимо для распознавателя JSP, но совсем не нужно, когда мы работаем с Thymeleaf.
  2. Префикс и суффикс работают аналогично атрибутам с одинаковыми именами в объектах Thymeleaf TemplateResolver.
  3. order устанавливает порядок, в котором ViewResolver будет запрашиваться в цепочке.
  4. viewNames позволяет определять (с подстановочными знаками) имена представлений, которые будут разрешаться этим ViewResolver.

3.2 Views и View Resolvers в Thymeleaf

Thymeleaf предлагает реализации для двух интерфейсов, упомянутых выше:
  1. org.thymeleaf.spring4.view.ThymeleafView
  2. org.thymeleaf.spring4.view.ThymeleafViewResolver
Эти два класса будут отвечать за обработку шаблонов Thymeleaf в результате выполнения контроллеров.

Конфигурация Resolver Thymeleaf View очень похожа на 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;
}

…или в 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>

Параметр templateEngine, конечно же, является объектом SpringTemplateEngine, который мы определили в предыдущей главе. Два других (order и viewNames) являются необязательными и имеют то же значение, что и в JSP ViewResolver, который мы видели ранее.

Обратите внимание, что нам не нужны префиксные или суффиксные параметры, потому что они уже указаны в Template Resolver (который, в свою очередь, передается в Template Engine).

А что, если мы хотим определить bean-компонент View и добавить к нему несколько статических переменных? Легко, просто определите для него прототип:

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

Сделав это, вы сможете запросить этот компонент, выбрав его по имени (в данном случае mainView).

4. Spring Thyme Seed Starter Manager

Исходный код для примеров, показанных в этой и последующих главах этого руководства, можно найти в репозитории GitHub Spring Seyme Seed Starter Manager.

4.1 Концепция

Касательно Thymeleaf — мы большие поклонники thyme, и каждый spring мы готовим наши стартовые наборы с хорошей почвой и нашими любимыми семенами, сажаем их под испанское солнце и терпеливо ждем, пока наши новые растения вырастут.

Но в этом году нам надоело наклеивать ярлыки на стартовые контейнеры для семян, чтобы узнать, какие семена были в каждой ячейке контейнера, поэтому мы решили подготовить приложение, используя Spring MVC и Thymeleaf, чтобы помочь нам каталогизировать наши стартеры: Spring Thyme SeedStarter Менеджер.


Аналогично приложению Good Thymes Virtual Grocery, которое мы разработали в учебном пособии «Использование Thymeleaf», STSM позволит нам продемонстрировать наиболее важные аспекты интеграции Thymeleaf как механизма шаблонов для Spring MVC.

4.2 Бизнес слой

Нам понадобится очень простой бизнес-уровень для нашего приложения. Прежде всего, давайте посмотрим на наши модельные объекты:

image
Пара очень простых классов обслуживания обеспечит необходимые бизнес-методы. Подобно:

@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);
    }
}

И:

@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 Spring MVC configuration

Затем нам нужно настроить конфигурацию Spring MVC для приложения, которая будет включать не только стандартные артефакты Spring MVC, такие как обработка ресурсов или сканирование аннотаций, но также создание экземпляров Template Engine и 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 The Controller

Конечно, нам также понадобится контроллер для нашего приложения. Поскольку STSM будет содержать только одну веб-страницу со списком начальных значений и форму для добавления новых, мы напишем только один класс контроллера для всех взаимодействий сервера:
@Controller
public class SeedStarterMngController {

    @Autowired
    private VarietyService varietyService;
    
    @Autowired
    private SeedStarterService seedStarterService;
    ...
}

Теперь давайте посмотрим, что мы можем добавить к этому классу контроллера.

Атрибуты модели

Сначала мы добавим некоторые атрибуты модели, которые нам понадобятся на странице:

@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();
}

Mapped методы

А теперь самая важная часть контроллера, отображаемые (mapped ) методы: один для отображения страницы формы, а другой для обработки добавления новых объектов 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 Configuring a Conversion Service

Чтобы обеспечить простое форматирование объектов Date, а также объектов Variety в нашем слое представления, мы настроили наше приложение таким образом, чтобы объект Spring ConversionService был создан и инициализирован (расширяемым WebMvcConfigurerAdapter) с помощью пары необходимых нам объектов форматирования. 
Посмотри еще раз:

@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();
}

Spring formatters are implementations of the org.springframework.format.Formatter interface. For more information on how the Spring conversion infrastructure works, see the docs at spring.io.

Давайте посмотрим на DateFormatter, который форматирует даты в соответствии со строкой форматирования, присутствующей в ключе сообщения date.format наших 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 автоматически преобразует между нашими объектами Variety и способом, которым мы хотим использовать их в наших формах (в основном, по значениям их полей id):

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() : "");
    }
}

Мы узнаем больше о том, как эти средства форматирования влияют на способ отображения наших данных в дальнейшем.


Смотри также популярное:

Зачем нужна Java. http://fetisovvs.blogspot.com/2014/07/java.html
Когда Java наконец помрёт, что с этим делать и что будет с JPoint. https://fetisovvs.blogspot.com/2018/11/java-jpoint-java.html
Разбор основных концепций параллелизма. http://fetisovvs.blogspot.com/2018/04/java.html
Первый контакт с «var» в Java 10. http://fetisovvs.blogspot.com/2018/01/var-java-10-java.html
JAVA 9. Что нового? http://fetisovvs.blogspot.com/2017/10/java-9-java.html
Руководство по Java 9 для тех, кому приходится работать с legacy-кодом. http://fetisovvs.blogspot.com/2018/08/java-9-legacy-java.html
Концепции объектно-ориентированного программирования — ООП в Java. http://fetisovvs.blogspot.com/2017/01/java-java.html
Анимации в Android по полочкам (Часть 1. Базовые анимации). http://fetisovvs.blogspot.com/2018/02/android-1-java.html
Двести пятьдесят русскоязычных обучающих видео докладов и лекций о Java. http://fetisovvs.blogspot.com/2015/12/java-5-java-java.html
Абстрактные классы и методы. http://fetisovvs.blogspot.com/2017/02/java.html
Полное руководство по Java Reflection API. Рефлексия на примерах. http://fetisovvs.blogspot.com/2017/02/java-reflection-api-java.html
Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. http://fetisovvs.blogspot.com/2017/10/java-java.html
Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. (Часть 3). http://fetisovvs.blogspot.com/2017/10/java-3-java.html
ТОП-3 способа конвертировать массив в ArrayList. Пример на Java. http://fetisovvs.blogspot.com/2016/09/3-arraylist-java-java.html
Ввод–вывод в Java. http://fetisovvs.blogspot.com/2016/05/java-java_28.html
Java Challengers #2: Сравнение строк. https://fetisovvs.blogspot.com/2018/11/java-challengers-2-java.html
Enum-Всемогущий. http://fetisovvs.blogspot.com/2017/02/enum-java.html
Массивы в Java. Создание и обработка. http://fetisovvs.blogspot.com/2017/10/java-java_18.html
Arrays, Collections: Алгоритмический минимум. http://fetisovvs.blogspot.com/2017/12/arrays-collections.html
Популярные методы для работы с Java массивами. http://fetisovvs.blogspot.com/2016/09/java-java_29.html
Пример использования метода replace в Java. Как заменить символ в строке? http://fetisovvs.blogspot.com/2017/01/replace-java-java.html
Класс Scanner в Java — описание и пример использования. http://fetisovvs.blogspot.com/2017/01/scanner-java-java.html
Пример использования метода trim в Java: как удалить пробелы в начале и конце строки? http://fetisovvs.blogspot.com/2017/01/trim-java-java.html
Spark — Потрясающий веб-микрофреймворк для Java. http://fetisovvs.blogspot.com/2017/10/spark-java-java.html
Чтение и запись CSV файла с помощью SuperCSV. http://fetisovvs.blogspot.com/2017/01/csv-supercsv-java-java.html
Конструкция try/catch/finally (исключения). http://fetisovvs.blogspot.com/2017/01/trycatchfinally-java.html
1000+ часов видео по Java на русском. http://fetisovvs.blogspot.nl/2017/06/1000-java-java.html
Раздача халявы: нетормозящие треды в Java. Project Loom. http://fetisovvs.blogspot.com/2018/09/java-project-loom-java.html
Шпаргалка Java программиста 7.1 Типовые задачи: Оптимальный путь преобразования InputStream в строку. http://fetisovvs.blogspot.com/2016/04/java-71-inputstream-java.html
Шпаргалки Java программиста 10: Lombok. http://fetisovvs.blogspot.nl/2017/12/java-10-lombok-java.html
Шпаргалки Java программиста 9: Java SE — Шпаргалка для собеседований и повторений. http://fetisovvs.blogspot.com/2017/12/java-9-java-se-java.html
Шпаргалка Java программиста 8. Библиотеки для работы с Json (Gson, Fastjson,
LoganSquare, Jackson, JsonPath и другие). http://fetisovvs.blogspot.com/2016/04/java-8-json-gson-fastjson-logansquare.html
Java 8 и паттерн Стратегия. http://fetisovvs.blogspot.com/2018/03/java-8-java.html
Java EE Concurency API. http://fetisovvs.blogspot.com/2018/08/java-ee-concurency-api-java.html
Реализация ООП-наследования в классах, работающих с SQL и MS Entity Framework. http://fetisovvs.blogspot.com/2017/02/sql-ms-entity-framework.html
Как установить соединение с СУБД MySQL в IntelliJ IDEA в редакции Community. http://fetisovvs.blogspot.com/2016/04/mysql-intellij-idea-community-java.html
TDD приложений на Spring Boot: работа с базой данных. https://fetisovvs.blogspot.com/2018/12/tdd-spring-boot-java.html
Максимально простой в поддержке способ интеграции java-клиента с java-сервером. http://fetisovvs.blogspot.com/2018/09/java-java-java.html
Как с помощью maven работать с библиотеками, которых в maven нет. http://fetisovvs.blogspot.com/2017/03/maven-maven-java.html
Проекты по созданию компиляторов из Java в JavaScript и исполняемые файлы. http://fetisovvs.blogspot.com/2018/01/java-javascript-java.html
Реактивное программирование с JAX-RS. http://fetisovvs.blogspot.com/2018/09/jax-rs-java.html
Компактные строки в Java 9. https://fetisovvs.blogspot.com/2018/10/java-9-java.html
Динамический прокси Java: что это и как им пользоваться? https://fetisovvs.blogspot.com/2018/12/java-java.html
Абстрактный CRUD от репозитория до контроллера: что ещё можно сделать при помощи Spring + Generics. http://fetisovvs.blogspot.com/2018/09/crud-spring-generics-java.html
Диагностика утечек памяти в Java. http://fetisovvs.blogspot.com/2017/03/java-java_18.html
Spring AOP и JavaConfig в плагинах для Atlassian Jira. http://fetisovvs.blogspot.com/2018/04/spring-aop-javaconfig-atlassian-jira.html
Блеск и нищета Java для настольных систем. http://fetisovvs.blogspot.com/2018/04/java-haulmont-java.html
Разбор задачек от Одноклассников на JPoint 2018. http://fetisovvs.blogspot.com/2018/04/jpoint-2018-java.html
Программируем… выход из лабиринта. http://fetisovvs.blogspot.com/2015/10/java.html
Основы работы с IntelliJ IDEA. Интерфейс программы. http://fetisovvs.blogspot.com/2016/09/intellij-idea-java.html
Ускоряем время сборки и доставки java web приложения. http://fetisovvs.blogspot.com/2018/03/java-web-java.html
Открытый урок Java Enterprise «CDI in action». http://fetisovvs.blogspot.com/2018/09/java-enterprise-cdi-in-action-java.html
«Мы все стремимся к сложности, а потом с ней боремся»: интервью с Венкатом Субраманиамом. http://fetisovvs.blogspot.com/2018/09/java_16.html

Комментариев нет:

Отправить комментарий