ZetCode-Spring-教程-一-

ZetCode Spring 教程(一)

原文:ZetCode

协议:CC BY-NC-SA 4.0

Spring @RequestHeader教程

原文: http://zetcode.com/spring/requestheader/

Spring @RequestHeader教程展示了如何使用@RequestHeader注解将方法参数绑定到请求标头。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring @RequestHeader

@RequestHeader注解将请求标头值绑定到方法参数。 如果方法参数为MapMultiValueMap<String, String>HttpHeaders,则将使用所有标头名称和值填充映射。

Spring @RequestHeader示例

该应用将请求正文标头绑定到方法参数。 使用curl工具创建请求。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
│           logback.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springrequestheader</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

我们在pom.xml中声明必要的依赖关系。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

}

WebConfig通过@EnableWebMvc启用 Spring MVC 注解,并为com.zetcode包配置组件扫描。

com/zetcode/controller/MyController.java

package com.zetcode.controller;
package com.zetcode.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class MyController {

    private static final Logger logger = LoggerFactory.getLogger(MyController.class);

    @GetMapping(value = "/agent")
    @ResponseStatus(value = HttpStatus.OK)
    public void client(@RequestHeader(value="User-Agent") String userAgent) {

        logger.info("User agent is: {}", userAgent);
    }

    @GetMapping(value = "/all")
    @ResponseStatus(value = HttpStatus.OK)
    public void all(@RequestHeader Map<String, String> headers) {

        logger.info("All headers: {}", headers);
    }
}

我们有两个映射。 第一个映射确定用户代理,第二个映射找出所有发送的请求标头。

public void client(@RequestHeader(value="User-Agent") String userAgent) {

使用@RequestHeader的 value 参数,我们查找特定的标头; 在我们的例子中是User-Agent

public void all(@RequestHeader Map<String, String> headers) {

提供映射时,我们会检索所有标头。

$ mvn jetty:run

我们启动服务器。

$ curl localhost:8080/agent

我们创建对第一个映射的请求。

08:26:29.926 INFO  com.zetcode.controller.MyController - User agent is: curl/7.55.1    

我们得到这个日志。

$ curl localhost:8080/all

我们调用第二个映射。

08:27:26.564 INFO  com.zetcode.controller.MyController - All headers: {User-Agent=curl/7.55.1, Accept=*/*, Host=localhost:8080}

我们记录了三个标头。

在本教程中,我们使用@RequestHeader注解将请求标头绑定到方法参数。

您可能也对这些相关教程感兴趣: Spring @GetMapping 教程Spring @RequestBody 教程Java 教程或列出所有 Spring 教程

Spring Cookies 教程

原文: http://zetcode.com/spring/cookies/

Spring Cookies 教程展示了如何在 Spring 应用中使用 Cookie。 使用@CookieValue注解读取 Cookie。

Spring 是用于创建企业应用的流行 Java 应用框架。

Cookies

Cookie 是服务器发送到用户的 Web 浏览器的一小段数据。 浏览器可以存储它,并将其与下一个请求一起发送回同一服务器。

Cookies 主要用于会话管理,个性化和跟踪。

@CookieValue

@CookieValue是一个注解,指示方法参数应绑定到 HTTP cookie。

HttpCookie

HttpCookie将 HTTP cookie 表示为与"Cookie"请求标头的内容一致的名称/值对。 ResponseCookie子类具有"Set-Cookie"响应标题中预期的其他属性。

以下示例创建一个写入和读取 Cookie 的 Spring Web 应用。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
│           logback.xml
└───test
    └───java

这是 Spring 应用的项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>cookiesex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

我们声明项目依赖项。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

DispatcherServlet是 Spring Web 应用的前端控制器,已注册在MyWebInitializer中。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig {

}

WebConfig通过@EnableWebMvc启用 Spring MVC 注解,并为com.zetcode包配置组件扫描。

com/zetcode/MyController.java

package com.zetcode.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    private static final Logger logger = LoggerFactory.getLogger(MyController.class);

    @ResponseStatus(value = HttpStatus.OK)
    @GetMapping(value = "/readCookie")
    public void readCookie(@CookieValue(value = "fav-col",
            defaultValue = "unknown") String favColour) {

        logger.info("Favourite colour: {}", favColour);
    }

    @ResponseStatus(value = HttpStatus.OK)
    @GetMapping(value = "/writeCookie")
    public ResponseEntity writeCookie() {

        var favColour = "steelblue";
        var cookie = ResponseCookie.from("fav-col", favColour).build();

        return ResponseEntity.ok()
                .header(HttpHeaders.SET_COOKIE, cookie.toString())
                .build();
    }
}

我们有两个 GET 映射。 第一个映射读取一个 cookie,第二个映射写入一个 cookie。

public void readCookie(@CookieValue(value = "fav-col",
        defaultValue = "unknown") String favColour) {

我们使用@CookieValue读取 Cookie 值。 如果未设置 cookie 或过期,则为默认值。

var favColour = "steelblue";
var cookie = ResponseCookie.from("fav-col", favColour).build();

return ResponseEntity.ok()
        .header(HttpHeaders.SET_COOKIE, cookie.toString())
        .build();

我们使用ResponseCookie创建一个 cookie,并将其设置为响应头。

$ mvn jetty:run

我们启动 Jetty 服务器。 现在,首先将浏览器定位到localhost:8080/writeCookie,然后通过导航到localhost:8080/readCookie来读取 cookie。

在本教程中,我们在 Spring 中使用 cookie。 您可能也对相关教程感兴趣: Spring @RequestMapping教程Spring @RequestHeader教程Java 教程或列出所有 Spring 教程

Spring 资源教程

原文: http://zetcode.com/spring/resource/

Spring Resource教程展示了如何使用Resource在 Spring 应用中使用各种资源。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring 资源

Resource从基础资源的实际类型中抽象出来,例如文件或类路径资源。 它可以用来标识本地或远程资源。

Spring ApplicationContext包含getResource()方法,该方法返回指定资源类型的资源句柄。 它可以是类路径,文件或 URL 资源。

Spring 资源示例

该应用使用 Spring 的Resource来读取本地文件和远程网页。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           └───service
│   │                   MyService.java
│   └───resources
│           logback.xml
│           words.txt
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>resourceex</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency> 

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/words.txt

clean
sky
forest
blue
crystal
cloud
river

words.txt文件包含几个单词。

com/zetcode/MyService.java

package com.zetcode.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

@Service
public class MyService {

    private static final Logger logger = LoggerFactory.getLogger(MyService.class);

    @Autowired
    private ApplicationContext ctx;

    public void readWebPage() {

        var res = ctx.getResource("http://webcode.me");

        try (var is = new InputStreamReader(res.getInputStream());
                var bis = new BufferedReader(is)) {

            bis.lines().forEach(System.out::println);

        } catch (IOException ex) {
            logger.warn("{}", ex);
        }
    }

    public void readFile() {

        // var res = ctx.getResource("file:C:/Users/Jano/Documents/words.txt");
        var res = ctx.getResource("classpath:words.txt");

        try (var is = new InputStreamReader(res.getInputStream());
                var bis = new BufferedReader(is)) {

            bis.lines().forEach(System.out::println);

        } catch (IOException ex) {
            logger.warn("{}", ex);
        }
    }
}

MyService有两种读取网页和本地文本文件的方法。

@Autowired
private ApplicationContext ctx;

我们注入ApplicationContext。 我们使用其getResource()方法来获取资源处理器。

var res = ctx.getResource("http://webcode.me");

我们从网页上获得了Resource

// var res = ctx.getResource("file:C:/Users/Jano/Documents/words.txt");
var res = ctx.getResource("classpath:words.txt");

我们可以从绝对文件路径或类路径获取Resource

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.service.MyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = "com.zetcode")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    @Autowired
    private MyService myService;

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(Application.class);
        var app = ctx.getBean(Application.class);

        app.run();
        ctx.close();
    }

    public void run() {

        myService.readWebPage();
        myService.readFile();
    }
}

这是主要的应用类。

@Autowired
private MyService myService;

使用@Autowired将服务 bean 注入到类中。

myService.readWebPage();
myService.readFile();

我们称为myService方法。

在本教程中,我们展示了如何使用Resource来读取本地文本文件和网页。

您可能也对这些相关教程感兴趣: Spring @Qualifier注解教程Spring 单例范围 beanSpring C-命名空间教程Spring BeanDefinitionBuilder教程Spring bean 引用教程Java 教程

Spring 重定向教程

原文: http://zetcode.com/spring/redirect/

Spring 重定向教程展示了如何在 Spring Web 应用中重定向请求。

Spring 是用于创建企业应用的流行 Java 应用框架。

重定向

视图名称中的特殊redirect:前缀将重定向到其他 URL。 最终效果与控制器已返回RedirectView的效果相同。 重定向应用于发布/重定向/获取(PRG)场景; PGR 是一种 Web 开发设计模式,可防止重复提交表单。 默认情况下,发送状态代码 302。 如果要更改,可以使用@ResponseStatus注解处理器方法的返回类型。

RedirectAttributesModel接口的一种特殊化,控制器可以用来选择重定向方案的属性。

重定向与转发

基本上可以通过三种方式处理请求:a)由 Spring 在控制器动作中解决,b)转发至其他控制器动作,c)重定向至客户端以获取另一个 URL。

向前:

  • 由 Spring 内部执行
  • 浏览器完全不知道转发,因此其原始 URL 保持不变
  • 浏览器重新加载结果页面会重复原始请求,并带有原始 URL
  • 请求中发送的数据可用于转发的操作

重定向:

  • 是一个两步过程
  • Spring 指示浏览器获取另一个 URL,该 URL 与原始 URL 不同
  • 浏览器重新加载第二个 URL 不会重复原始请求,而是获取第二个 URL
  • 在原始请求范围内发送的数据不适用于第二个请求

Spring 重定向示例

提交表单后,以下应用使用重定向到其他 URL。 它使用redirect:前缀执行重定向。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───bean
│   │           │       User.java
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
│       │   logback.xml
│       │
│       └───templates
│               addUser.html
│               showUserAdded.html
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springredirectex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

pom.xml中,我们具有必要的依赖项。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {

        var templateResolver = new SpringResourceTemplateResolver();

        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("classpath:/templates/");
        templateResolver.setSuffix(".html");

        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {

        var templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);

        return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver() {

        var resolver = new ThymeleafViewResolver();
        var registry = new ViewResolverRegistry(null, applicationContext);

        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);

        return resolver;
    }
}

WebConfig配置 Thymeleaf 模板引擎。 我们将模板文件的位置设置为classpath上的templates目录。 (resources在类路径上。)

com/zetcode/bean/User.java

package com.zetcode.bean;

public class User {

    private String name;
    private String occupation;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getOccupation() {
        return occupation;
    }

    public void setOccupation(String occupation) {
        this.occupation = occupation;
    }

    @Override
    public String toString() {

        final StringBuilder sb = new StringBuilder("User{");
        sb.append("name='").append(name).append('\'');
        sb.append(", occupation='").append(occupation).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

这是User bean。 它填充有来自表单的数据。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import com.zetcode.bean.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@Controller
public class MyController {

    private static final Logger logger = LoggerFactory.getLogger(MyController.class);

    @GetMapping("/addUser")
    public String sendForm(User user) {

        return "addUser";
    }

    @PostMapping("/addUser")
    public String processForm(User user, RedirectAttributes redirectAttrs) {

        logger.info("User {} has been saved", user.getName());

        redirectAttrs.addAttribute("name", user.getName());

        return "redirect:userAdded";
    }

    @GetMapping("/userAdded")
    public String userAdded() {

        return "showUserAdded";
    }
}

MyController提供请求路径和处理器方法之间的映射。

@GetMapping("/addUser")
public String sendForm(User user) {

    return "addUser";
}

该映射将表单发送给用户。

@PostMapping("/addUser")
public String processForm(User user, RedirectAttributes redirectAttrs) {

    logger.info("User {} has been saved", user.getName());

    redirectAttrs.addAttribute("name", user.getName());

    return "redirect:userAdded";
}

此映射处理表单。 新用户被“保存”并执行重定向。 用户名通过addAttribute()添加到重定向属性中。

resources/templates/addUser.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Add user</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>

<h1>Add User</h1>

<form action="#" th:action="@{/addUser}" th:object="${user}" method="post">
    <p>
        Name: <input type="text" th:field="*{name}">
    </p>
    <p>
        Occupation: <input type="text" th:field="*{occupation}">
    </p>
    <p>
        <input type="submit" value="Submit"/> <input type="reset" value="Reset">
    </p>
</form>

</body>
</html>

addUser.html模板向用户提供表格。 输入的字段将自动插入到User's属性中。

resources/templates/showUserAdded.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>User saved</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>

<h2>User has been saved</h2>

<p th:text="'Name: ' + ${#request.getParameter('name')}"></p>
<a href="/addUser">Add another user</a>

</body>
</html>

提交表单后,此模板向用户显示一条消息。 它使用${#request.getParameter('name')}读取redirect属性。

$ mvn jetty:run

我们运行服务器并找到localhost:8080/addUser

在本教程中,我们在 Spring 控制器中执行了重定向。

您可能也对这些相关教程感兴趣: Spring 转发教程Java 教程或列出所有 Spring 教程

Spring 转发教程

原文: http://zetcode.com/spring/forward/

Spring 转发教程展示了如何在 Spring Web 应用中转发请求。

Spring 是用于创建企业应用的流行 Java 应用框架。

转发

视图名称中的特殊forward:前缀将转发到其他 URL。 转发 URL 可在同一服务器内部内部传输请求,而无需涉及客户端浏览器。 转发的执行频率少于重定向。

重定向与转发

基本上可以通过三种方式处理请求:a)由 Spring 在控制器动作中解决,b)转发至其他控制器动作,c)重定向至客户端以获取另一个 URL。

向前:

  • 由 Spring 内部执行
  • 浏览器完全不知道转发,因此其原始 URL 保持不变
  • 浏览器重新加载结果页面会重复原始请求,并带有原始 URL
  • 请求中发送的数据可用于转发的操作

重定向:

  • 是一个两步过程
  • Spring 指示浏览器获取另一个 URL,该 URL 与原始 URL 不同
  • 浏览器重新加载第二个 URL 不会重复原始请求,而是获取第二个 URL
  • 在原始请求范围内发送的数据不适用于第二个请求

Spring 转发的例子

提交表单后,以下应用使用转发到其他 URL。 它执行带有forward:前缀的转发。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
│       │   logback.xml
│       │
│       └───templates
│               show.ftl
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springforwardex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

pom.xml中,我们具有必要的依赖项。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public FreeMarkerViewResolver freemarkerViewResolver() {

        var resolver = new FreeMarkerViewResolver();
        resolver.setCache(true);
        resolver.setSuffix(".ftl");
        return resolver;
    }

    @Bean
    public FreeMarkerConfigurer freemarkerConfig() {

        var freeMarkerConfigurer = new FreeMarkerConfigurer();
        freeMarkerConfigurer.setTemplateLoaderPath("classpath:/templates/");
        return freeMarkerConfigurer;
    }
}

WebConfig配置 Freemarker。 我们将模板文件的位置设置为classpath上的templates目录。 (resources在类路径上。)

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class MyController {

    private static final Logger logger = LoggerFactory.getLogger(MyController.class);

    @GetMapping(value = "/sendname")
    public String send(@RequestParam(defaultValue = "guest") String name, Model model) {

        logger.info("sendname called");

        model.addAttribute("name", name);

        return "forward:/newpage";
    }

    @GetMapping(value = "/newpage")
    public String newpage() {

        logger.info("newpage called");

        return "show";
    }
}

MyController提供了两个 GET 映射。

@GetMapping(value = "/sendname")
public String send(@RequestParam(defaultValue = "guest") String name, Model model) {

    logger.info("send name called");

    model.addAttribute("name", name);

    return "forward:/newpage";
}

的请求发送至/sendnamesend()操作处理。 读取请求参数并将其添加到模型。 最后,它被转发到新的控制器操作。

@GetMapping(value = "/newpage")
public String newpage() {

    logger.info("newpage called");

    return "show";
}

newpage()操作将请求解析为show视图。

resources/templates/show.ftl

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Show</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>

<p>
User name: ${name}
</p>

</body>
</html>

show.ftl显示用户名。

$ mvn jetty:run

我们运行服务器并找到localhost:8080/sendname?name=Peter

09:52:11.636 INFO  com.zetcode.controller.MyController - sendname called 
09:52:11.653 INFO  com.zetcode.controller.MyController - newpage called 

服务器日志包含这些行。

在本教程中,我们在 Spring 控制器中执行了正向操作。

您可能也对这些相关教程感兴趣: Spring 重定向教程Java 教程或列出所有 Spring 教程

Spring ModelAndView教程

原文: http://zetcode.com/spring/modelandview/

Spring ModelAndView教程展示了如何在 Spring Web 应用的控制器中使用ModelAndView

Spring 是用于创建企业应用的流行 Java 应用框架。

ModelAndView

ModelAndView是 Web MVC 框架中ModelView的持有者。 这两类是截然不同的。 ModelAndView仅保留两者,以使控制器有可能在单个返回值中返回模型和视图。

该视图由ViewResolver对象解析; 该模型是存储在Map中的数据。

Spring ModelAndView示例

以下应用使用ModelAndView在 Spring 控制器中一步返回模型和视图。 我们使用 Freemarker 进行视图解析。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
│       │   logback.xml
│       └───templates
│               index.ftl
│               show.ftl
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springmodelandview</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

pom.xml中,我们具有必要的依赖项。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public FreeMarkerViewResolver freemarkerViewResolver() {

        var resolver = new FreeMarkerViewResolver();
        resolver.setCache(true);
        resolver.setSuffix(".ftl");
        return resolver;
    }

    @Bean
    public FreeMarkerConfigurer freemarkerConfig() {

        var freeMarkerConfigurer = new FreeMarkerConfigurer();
        freeMarkerConfigurer.setTemplateLoaderPath("classpath:/templates/");
        return freeMarkerConfigurer;
    }
}

WebConfig配置 FreeMarker 模板引擎。 我们将模板文件的位置设置为classpath上的templates目录。 (resources在类路径上。)

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Controller
public class MyController {

    @GetMapping(value = "/")
    public String home() {

        return "index";
    }

    @GetMapping(value = "/show")
    public ModelAndView show() {

        var mav = new ModelAndView();

        var now = LocalDateTime.now();
        var formatter = DateTimeFormatter.ISO_DATE_TIME;
        var dateTimeFormatted = formatter.format(now);

        mav.addObject("now", dateTimeFormatted);
        mav.setViewName("show");

        return mav;
    }
}

MyController提供了两个 GET 映射。

@GetMapping(value = "/show")
public ModelAndView show() {

show()方法返回ModelAndView

var mav = new ModelAndView();

var now = LocalDateTime.now();
var formatter = DateTimeFormatter.ISO_DATE_TIME;
var dateTimeFormatted = formatter.format(now);

mav.addObject("now", dateTimeFormatted);
mav.setViewName("show");

return mav;

创建一个ModelAndView并填充数据。 数据是格式化的日期时间对象。 视图名称由setViewName()设置。 Spring 将视图名称解析为show.ftl

resources/templates/index.ftl

<!DOCTYPE html>
<html>
    <head>
        <title>Home</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>

        <p>
            <a href="show">Show today's datetime</a>
        </p>

    </body>
</html>

主页包含一个链接,以显示今天的日期时间。

resources/templates/show.ftl

<!DOCTYPE html>
<html>
    <head>
        <title>Today's date</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>

        <p>
            Today is: ${now}
        </p>

    </body>
</html>

show.ftl视图中,我们使用${}语法显示当前日期时间。

$ mvn jetty:run

我们运行服务器并找到localhost:8080以获取具有链接的主页。

在本教程中,我们使用ModelAndView来组织模型和视图。

您可能也对这些相关教程感兴趣: Spring @Configuration教程Spring @GetMapping教程Java 教程或列出所有 Spring 教程

Spring MessageSource教程

原文: http://zetcode.com/spring/messagesource/

Spring MessageSource教程展示了如何在 Spring 应用中使用MessageSource转换消息。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring MessageSource

MessageSource用于解析消息,并支持消息的参数化和国际化。 Spring 包含两个内置的MessageSource实现:ResourceBundleMessageSourceReloadableResourceBundleMessageSource。 后者能够重新加载消息定义,而无需重新启动虚拟机。

Spring MessageSource示例

以下应用包含英语和德语消息。 它使用内置的ResourceBundleMessageSource

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           └───config
│   │                   AppConfig.java
│   └───resources
│       │   logback.xml
│       └───messages
│               label.properties
│               label_de.properties
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>messagesource</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/messages/labels.properties

l1=Earth
l2=Hello {0}, how are you?

这些是英文信息。 第二个属性接收一个参数。

resources/messages/labels_de.properties

l1=Erde
l2=Hallo {0}, wie geht's?

这些是德语信息。

com/zetcode/config/AppConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;

@Configuration
public class AppConfig {

    @Bean
    public ResourceBundleMessageSource messageSource() {

        var source = new ResourceBundleMessageSource();
        source.setBasenames("messages/label");
        source.setUseCodeAsDefaultMessage(true);

        return source;
    }
}

AppConfig配置ResourceBundleMessageSourcesetBasenames()告诉在哪里查找消息定义。

com/zetcode/Application.java

package com.zetcode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import java.util.Locale;

@ComponentScan(basePackages = "com.zetcode")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    @Autowired
    private MessageSource messageSource;

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(Application.class);

        var app = ctx.getBean(Application.class);
        app.run();

        ctx.close();
    }

    public void run() {

        logger.info("Translated messages:");
        logger.info("{}", messageSource.getMessage("l1",
                null, Locale.GERMAN));
        logger.info("{}", messageSource.getMessage("l1",
                null, Locale.ENGLISH));

        logger.info("Translated parameterized messages:");
        logger.info("{}", messageSource.getMessage("l2",
                new Object[] {"Paul Smith"}, Locale.GERMAN));
        logger.info("{}", messageSource.getMessage("l2",
                new Object[] {"Paul Smith"}, Locale.ENGLISH));
    }
}

该应用将普通消息和参数化消息打印到控制台。

@Autowired
private MessageSource messageSource;

我们注入在AppConfig中生成的MessageSource

logger.info("{}", messageSource.getMessage("l1",
    null, Locale.GERMAN));

getMessage()将属性名称作为第一个参数。 第二个参数是null,因为消息没有任何参数。 第三个参数是语言环境。

logger.info("{}", messageSource.getMessage("l2",
    new Object[] {"Paul Smith"}, Locale.GERMAN));

在这里,我们还为消息提供了一个参数。

$ mvn -q exec:java
22:08:27.984 INFO  com.zetcode.Application - Translated messages:
22:08:27.984 INFO  com.zetcode.Application - Erde
22:08:27.984 INFO  com.zetcode.Application - Earth
22:08:27.984 INFO  com.zetcode.Application - Translated parameterized messages:
22:08:27.984 INFO  com.zetcode.Application - Hallo Paul Smith, wie gehts?
22:08:27.984 INFO  com.zetcode.Application - Hello Paul Smith, how are you?

我们运行该应用。

在本教程中,我们展示了如何在 Spring 应用中使用ResourceBundleMessageSource

您可能也对这些相关教程感兴趣: Java ResourceBundle教程Spring @ComponentScan教程Java 教程或列出所有 Spring 教程

Spring AnnotationConfigApplicationContext

http://zetcode.com/spring/annotationconfigapplicationcontext/

Spring AnnotationConfigApplicationContext教程展示了如何在 Spring 应用中使用AnnotationConfigApplicationContext

Spring 是流行的 Java 应用框架。

AnnotationConfigApplicationContext

AnnotationConfigApplicationContext是一个独立的应用上下文,它接受带注解的类作为输入。 例如@Configuration@Component。 可以使用scan()查找 Bean,也可以使用register()注册 Bean。

Spring AnnotationConfigApplicationContext示例

以下示例使用AnnotationConfigApplicationContext来构建独立的 Spring 应用。 它有一个 Spring bean DateTimeService,位于scan()中。

pom.mxl
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           └───bean
│   │                   DateTimeService.java
│   └───resources
│           logback.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>annotappctx</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

这是我们 Spring 应用的 Maven 构建文件。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

这是 Logback 配置文件。

com/zetcode/bean/DateTimeService.java

package com.zetcode.bean;

import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

@Service
public class DateTimeService {

    public LocalDate getDate() {

        return LocalDate.now();
    }

    public LocalTime getTime() {

        return LocalTime.now();
    }

    public LocalDateTime getDateTime() {

        return LocalDateTime.now();
    }
}

DateTimeService是提供数据和时间服务的服务类。 它以@Service构造型装饰,这使它在扫描过程中被检测到。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.bean.DateTimeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    @Autowired
    private DateTimeService dateTimeService;

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext();
        ctx.scan("com.zetcode");
        ctx.refresh();

        var bean = ctx.getBean(Application.class);
        bean.run();

        ctx.close();
    }

    public void run() {

        logger.info("Current time: {}", dateTimeService.getTime());
        logger.info("Current date: {}", dateTimeService.getDate());
        logger.info("Current datetime: {}", dateTimeService.getDateTime());
    }
}

我们设置了应用并注入了DateTimeService。 我们称这三种服务方法。

@Component
public class Application {

Application也是用原型装饰,这次是@Component。 Spring 也会检测到它。 我们需要调用其run()方法以超出静态上下文。

@Autowired
private DateTimeService dateTimeService;    

服务类注入@Autowired

var ctx = new AnnotationConfigApplicationContext();
ctx.scan("com.zetcode");
ctx.refresh();

创建一个新的AnnotationConfigApplicationContextscan()方法扫描com.zetcode包及其子包中的带注解的类,以生成 bean。 我们需要调用refresh()方法来完成该过程。

public void run() {

    logger.info("Current time: {}", dateTimeService.getTime());
    logger.info("Current date: {}", dateTimeService.getDate());
    logger.info("Current datetime: {}", dateTimeService.getDateTime());
}

我们获取当前日期,时间和日期时间。

$ mvn package
$ mvn -q exec:java
19:25:12.842 INFO  com.zetcode.Application - Current time: 19:25:12.842639200
19:25:12.842 INFO  com.zetcode.Application - Current date: 2019-01-05
19:25:12.842 INFO  com.zetcode.Application - Current datetime: 2019-01-05T19:25:12.842639200

我们运行该应用。

在本教程中,我们使用AnnotationConfigApplicationContext创建了一个新的独立 Spring 应用。

您可能也对相关教程感兴趣:独立的 Spring 应用Spring @ComponentScan教程Java 教程

Spring BeanFactoryPostProcessor教程

原文: http://zetcode.com/spring/beanfactorypostprocessor/

Spring BeanFactoryPostProcessor教程展示了如何使用BeanFactoryPostProcessor来修改应用上下文的 Bean 定义。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring BeanFactoryPostProcessor

在实际创建 bean 之前,Spring BeanFactoryPostProcessor会处理 bean 的 bean 定义或配置元数据。 使用BeanFactoryPostProcessor,我们可以修改现有的 bean 定义或创建新的 bean 定义。

Spring 提供了BeanFactoryPostProcessor的一些内置实现。 例如,PropertyPlaceholderConfigurer是一种后处理器,可以从外部文件读取属性。

Spring BeanFactoryPostProcessor示例

以下应用使用BeanFactoryPostProcessor添加新的 bean 定义。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           │
│   │           └───config
│   │                   AppConfig.java
│   └───resources
│           logback.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>beanfactorypostprocessorex</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency> 

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/config/AppConfig.java

package com.zetcode.config;

import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public static BeanFactoryPostProcessor beanFactoryPostProcessor() {
        return factory -> {

            var registry = (BeanDefinitionRegistry) factory;

            registry.registerBeanDefinition("myBean",
                    BeanDefinitionBuilder.genericBeanDefinition(String.class)
                            .addConstructorArgValue("This is myBean")
                            .getBeanDefinition()
            );
        };
    }
}

AppConfig是应用配置类。 使用@Bean创建一个BeanFactoryPostProcessor,它注册一个内置的java.lang.String类型的新简单 bean。 新 bean 已向registerBeanDefinition()注册。

com/zetcode/Application.java

package com.zetcode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new GenericXmlApplicationContext("my-beans.xml");

        logger.info("{}", ctx.getBean("myBean"));

        ctx.close();
    }
}

Application中,我们获取已注册的 bean 并进行打印。

$ mvn -q exec:java
18:53:19.233 INFO  com.zetcode.Application - This is myBean

我们运行该应用。

在本教程中,我们展示了如何使用BeanFactoryPostProcessor注册新 bean。

您可能也对这些相关教程感兴趣: Spring @Qualifier注解教程Spring 单例范围 beanSpring C 命名空间教程Spring context:property-placeholder教程Spring BeanDefinitionBuilder教程Spring bean 引用教程Java 教程

Spring BeanFactory教程

原文: http://zetcode.com/spring/beanfactory/

Spring BeanFactory教程展示了如何在 Spring 应用中使用BeanFactory处理 Bean

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring BeanFactory

BeanFactory是应用组件的中央注册表。 它集中了应用组件的配置。 BeanFactory加载存储在配置源(例如 XML 文档或 Java 配置)中的 bean 定义。

Spring BeanFactory示例

该应用创建一个 bean 工厂,从 XML 配置文件加载 bean 定义,并在 bean 上应用后处理器。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │               Application.java
│   └───resources
│           database.properties
│           logback.xml
│           my-beans.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>beanfactory</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-version}</version>
        </dependency>        

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-contextspring-jdbc和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/database.properties

db.url=jdbc:h2:mem:testdb
db.username=testuser
db.password=s$cret

这些属性将通过 bean 后处理工厂插入到 bean 中。

resources/my-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <property name="url" value="${db.url}"></property>
        <property name="username" value="${db.username}"></property>
        <property name="password" value="${db.password}"></property>
    </bean>

</beans>

my-beans.xml文件声明一个dataSource bean。 ${}语法从外部属性文件插入值。

com/zetcode/Application.java

package com.zetcode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;

public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var factory = new DefaultListableBeanFactory();
        var reader = new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinitions(new ClassPathResource("my-beans.xml"));

        var cfg = new PropertyPlaceholderConfigurer();
        cfg.setLocation(new ClassPathResource("database.properties"));
        cfg.postProcessBeanFactory(factory);

        var dataSource = (SimpleDriverDataSource) factory.getBean("dataSource");

        logger.info("Url: {}", dataSource.getUrl());
        logger.info("User name: {}", dataSource.getUsername());
        logger.info("Password: {}", dataSource.getPassword());
    }
}

该应用创建一个BeanFactory并注册一个 bean。

var factory = new DefaultListableBeanFactory();
var reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(new ClassPathResource("my-beans.xml"));

创建了DefaultListableBeanFactory,它是BeanFactory的实现。 它使用XmlBeanDefinitionReadermy-beans.xml配置文件读取 bean。 Bean 定义已加载loadBeanDefinitions()

var cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new ClassPathResource("database.properties"));
cfg.postProcessBeanFactory(factory);

PropertyPlaceholderConfigurer将属性从database.properties文件插入到 bean 中。

var dataSource = (SimpleDriverDataSource) factory.getBean("dataSource");

我们使用getBean()从工厂获得了 Bean。

logger.info("Url: {}", dataSource.getUrl());
logger.info("User name: {}", dataSource.getUsername());
logger.info("Password: {}", dataSource.getPassword());

我们检索dataSource bean 属性。

$ mvn -q exec:java
10:02:30.701 INFO  com.zetcode.Application - Url: jdbc:h2:mem:testdb
10:02:30.701 INFO  com.zetcode.Application - User name: testuser
10:02:30.701 INFO  com.zetcode.Application - Password: s$cret

我们运行该应用。

在本教程中,我们展示了如何创建BeanFactory以及如何加载和后期处理 bean 定义。

您可能也对这些相关教程感兴趣: Spring BeanDefinitionBuilder教程Spring 单例范围 beanSpring 注入列表 XML 教程Spring BeanDefinitionBuilder教程Spring HikariCP 教程Java 教程

Spring @Bean注解教程

原文: http://zetcode.com/spring/bean/

Spring @Bean注解教程展示了如何使用@Bean注解在 Java 配置类中声明 bean。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring @Bean

@Bean注解指示带注解的方法产生要由 Spring 容器管理的 bean。 它是<bean/> XML 标签的直接模拟。 @Bean支持<bean/>提供的大多数属性,例如:init-methoddestroy-methodautowiringlazy-initdependency-checkdepends-onscope

Spring @Bean示例

该应用生成带有@Bean注解的 Spring 托管 bean。 它还为 bean 提供了一些别名。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           ├───bean
│   │           │       HelloMessage.java
│   │           └───config
│   │                   AppConfig.java
│   └───resources
│           logback.xml
│           messages.properties
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>beanannotation</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>      

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/message.properties

motd="Hello there!"

message.properties包含day属性的消息,由我们的HelloMessage bean 使用。 这为应用提供了更大的灵活性,并避免了将消息硬编码为 Java 代码。

com/zetcode/bean/HelloMessage.java

package com.zetcode.bean;

public class HelloMessage {

    private String message;

    public HelloMessage(String message) {

        this.message = message;
    }

    public String getMessage() {

        return message;
    }
}

HelloMessage bean 是使用@Bean注解方法创建的。

com/zetcode/config/AppCofig.java

package com.zetcode.config;

import com.zetcode.bean.HelloMessage;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource(value="messages.properties")
public class AppConfig {

    @Value("${motd}")
    private String message;

    @Bean(name={"myMessage", "motd"})
    public HelloMessage helloMessageProducer() {

        var helloMessage = new HelloMessage(message);

        return helloMessage;
    }
}

我们在AppConfig中定义了HelloMessage生产者。

@Configuration
@PropertySource(value="messages.properties")
public class AppConfig {

使用@Configuration,我们声明AppConfig是配置类。 @PropertySource注解允许我们通过@Value轻松使用messages.properties文件中的属性。

@Value("${motd}")
private String message;

我们将motd属性注入到message属性中。

@Bean(name={"myMessage", "motd"})
public HelloMessage helloMessageProducer() {

    var helloMessage = new HelloMessage(message);

    return helloMessage;
}

helloMessageProducer()产生一个新的HelloMessage bean。 它从外部属性获取消息。 @Bean注解使HelloMessage bean 由 Spring 生产和管理。 另外,我们给 Bean 两个别名。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.bean.HelloMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = "com.zetcode")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(Application.class);

        var msgBean1 = ctx.getBean(HelloMessage.class);
        logger.info("{}", msgBean1.getMessage());

        var msgBean2 = (HelloMessage) ctx.getBean("myMessage");
        logger.info("{}", msgBean2.getMessage());

        var msgBean3 = (HelloMessage) ctx.getBean("motd");
        logger.info("{}", msgBean3.getMessage());

        ctx.close();
    }
}

该应用带有@ComponentScan注解。 basePackages选项告诉 Spring 在com/zetcode包及其子包中查找组件。

var ctx = new AnnotationConfigApplicationContext(Application.class);

AnnotationConfigApplicationContext是 Spring 独立应用上下文。 它接受带注解的Application作为输入; 因此启用了扫描。

var msgBean1 = ctx.getBean(HelloMessage.class);
logger.info("{}", msgBean1.getMessage());

我们通过其类型来获取 bean。

var msgBean2 = (HelloMessage) ctx.getBean("myMessage");
logger.info("{}", msgBean2.getMessage());

var msgBean3 = (HelloMessage) ctx.getBean("motd");
logger.info("{}", msgBean3.getMessage());

在这里,我们通过别名获得相同的 bean。

$ mvn -q exec:java
14:39:29.324 INFO  com.zetcode.Application - "Hello there!" 
14:39:29.324 INFO  com.zetcode.Application - "Hello there!" 
14:39:29.324 INFO  com.zetcode.Application - "Hello there!" 

我们运行该应用。

在本教程中,我们使用了@Bean注解来生成托管的 Spring bean。

您可能也会对这些相关教程感兴趣: Spring 单例范围 beanSpring @ComponentScan教程Spring @Autowired教程Java 教程,或列出所有 Spring 教程

Spring context:property-placeholder教程

原文: http://zetcode.com/spring/propertyplaceholder/

Spring context:property-placeholder教程展示了如何使用context:property-placeholder标记来外部化 Spring 应用中的属性。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring 的context:property-placeholder

context:property-placeholder标签用于外部化单独文件中的属性。 它会自动配置PropertyPlaceholderConfigurer,从而替换${}占位符,这些占位符针对指定的属性文件(作为 Spring 资源位置)进行解析。

Spring context:property-placeholder示例

该应用使用context:property-placeholder来配置数据源的属性。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │               Application.java
│   └───resources
│           database.properties
│           logback.xml
│           my-beans.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>propertyplaceholder</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-version}</version>
        </dependency>        

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-contextspring-jdbc和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/database.properties

db.url=jdbc:h2:mem:testdb
db.username=testuser
db.password=s$cret

这些值在database.properties文件中外部化。 这种方法比将值直接放入 XML 文件中更为灵活。

resources/my-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="classpath:database.properties"/>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <property name="url" value="${db.url}"></property>
        <property name="username" value="${db.username}"></property>
        <property name="password" value="${db.password}"></property>
    </bean>

</beans>

context:property-placeholder指定属性文件的位置; 在我们的例子中,它是任何类路径目录中的database.properties文件。

<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
    <property name="url" value="${db.url}"></property>
    <property name="username" value="${db.username}"></property>
    <property name="password" value="${db.password}"></property>
</bean>    

定义了dataSource bean。 它通过${}语法从属性文件中获取其值。

com/zetcode/Application.java

package com.zetcode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;

public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new GenericXmlApplicationContext("my-beans.xml");

        var dataSource = (SimpleDriverDataSource) ctx.getBean("dataSource");

        logger.info("Url: {}", dataSource.getUrl());
        logger.info("User name: {}", dataSource.getUsername());
        logger.info("Password: {}", dataSource.getPassword());

        ctx.close();
    }
}

这是主要的应用类。 它检索dataSource bean 并打印其属性。

$ mvn -q exec:java
11:27:43.790 INFO  com.zetcode.Application - Url: jdbc:h2:mem:testdb 
11:27:43.790 INFO  com.zetcode.Application - User name: testuser 
11:27:43.790 INFO  com.zetcode.Application - Password: s$cret 

我们运行该应用。

在本教程中,我们展示了如何使用context:property-placeholder来外部化属性。

您可能也对这些相关教程感兴趣: Spring @Qualifier注解教程Spring 单例范围 beanSpring C-命名空间教程Spring BeanDefinitionBuilder教程Spring bean 引用教程Java 教程

Spring @PropertySource注解教程

原文: http://zetcode.com/spring/propertysource/

Spring @PropertySource注解教程显示了如何使用@PropertySource注解将属性包括到环境中以及如何使用@Value注入属性。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring @PropertySource

@PropertySource是方便的注解,用于将PropertySource包含到 Spring 的环境中,并允许通过@Value将属性注入类属性中。 (PropertySource是代表来自特定来源的一组属性对的对象。)

@PropertySource@Configuration一起使用。

Spring @PropertySource示例

该应用使用 Spring 的@PropertySourceapplication.properties文件中的属性包含到环境中,并将它们注入类属性中。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           └───config
│   │                   AppConfig.java
│   └───resources
│           application.properties
│           logback.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>propertysource</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency> 

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/application.properties

app.name=My application
app.version=1.1

application.properties文件中有两个属性。

com/zetcode/config/AppConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource(value = "application.properties", ignoreResourceNotFound = true)
public class AppConfig {

}

AppConfig是应用配置类。 @PropertySource将属性从application.properties注入到 Spring 的环境中。

com/zetcode/Application.java

package com.zetcode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.Environment;

@ComponentScan(basePackages = "com.zetcode")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    @Autowired
    private Environment env;

    @Value("${app.name}")
    private String appName;

    @Value("${app.version}")
    private String appVersion;

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(Application.class);
        var app = ctx.getBean(Application.class);

        app.run();

        ctx.close();
    }

    private void run() {

        logger.info("From Environment");
        logger.info("Application name: {}", env.getProperty("app.name"));
        logger.info("Application version: {}", env.getProperty("app.version"));

        logger.info("Using @Value injection");
        logger.info("Application name: {}", appName);
        logger.info("Application version: {}", appVersion);
    }
}

Application中,我们使用两种方法获得属性。

@Autowired
private Environment env;

我们注入Environment。 我们可以使用getProperty()方法检索属性。

@Value("${app.name}")
private String appName;

@Value("${app.version}")
private String appVersion;

我们将带有@Value注解的属性注入到属性中。

logger.info("From Environment");
logger.info("Application name: {}", env.getProperty("app.name"));
logger.info("Application version: {}", env.getProperty("app.version"));

检索属性的第一种方法是使用getProperty()方法从Environment

logger.info("Using @Value injection");
logger.info("Application name: {}", appName);
logger.info("Application version: {}", appVersion);

第二种方法是使用注入的属性。

$ mvn -q exec:java
15:00:20.653 INFO  com.zetcode.Application - From Environment 
15:00:20.668 INFO  com.zetcode.Application - Application name: My application 
15:00:20.668 INFO  com.zetcode.Application - Application version: 1.1 
15:00:20.668 INFO  com.zetcode.Application - Using @Value injection 
15:00:20.668 INFO  com.zetcode.Application - Application name: My application 
15:00:20.668 INFO  com.zetcode.Application - Application version: 1.1 

我们运行该应用。

在本教程中,我们展示了如何使用@PropertySource注解在 Spring 应用中方便地使用属性。

您可能也对这些相关教程感兴趣: Spring @Qualifier注解教程Spring @Configuration注解教程Spring context:property-placeholder教程,Java 教程,或列出所有 Spring 教程

Spring @ComponentScan教程

原文: http://zetcode.com/spring/componentscan/

Spring @ComponentScan教程显示了如何在 Spring 应用中启用组件扫描。 通过组件扫描,可以通过 Spring 容器自动检测咖啡豆。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring @ComponentScan

@ComponentScan注解启用 Spring 中的组件扫描。 Spring 会自动检测以@Component@Configuration@Service等构造型修饰的 Java 类。 使用@ComponentScanbasePackages属性指定应扫描哪些包装中的装饰豆。

@ComponentScan注解是<context:component-scan> XML 标签的替代方法。

Spring @ComponentScan示例

该应用允许使用@ComponentScan进行组件扫描。 我们有一个返回当前时间的服务 bean。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           └───service
│   │                   TimeService.java
│   └───resources
│           logback.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>componentscan</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>      

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/service/TimeService.java

package com.zetcode.service;

import org.springframework.stereotype.Service;

import java.time.LocalTime;

@Service
public class TimeService {

    public LocalTime getTime() {

        var now = LocalTime.now();

        return now;
    }
}

TimeService类带有@Service注解。 Spring 在组件扫描的帮助下将其注册为托管 Bean。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.service.TimeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@ComponentScan(basePackages = "com.zetcode")
@Configuration
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(Application.class);

        var timeService = (TimeService) ctx.getBean("timeService");
        logger.info("The time is {}", timeService.getTime());

        ctx.close();
    }
}

该应用带有@ComponentScan注解。 basePackages选项告诉 Spring 在com/zetcode包及其子包中查找组件。

var ctx = new AnnotationConfigApplicationContext(Application.class);

AnnotationConfigApplicationContext是 Spring 独立应用上下文。 它接受带注解的Application作为输入; 因此启用了扫描。

var timeService = (TimeService) ctx.getBean("timeService");
logger.info("The time is {}", timeService.getTime());

我们获取注册的服务 bean 并调用其方法。

$ mvn -q exec:java
10:57:01.912 INFO  com.zetcode.Application - The time is 10:57:01.912235800

我们运行该应用。

在本教程中,我们使用@ComponentScan启用了组件扫描。

您可能也对这些相关教程感兴趣: Spring BeanDefinitionBuilder教程Spring AnnotationConfigApplicationContextSpring 单例范围 beanSpring @Bean注解教程Spring @Configuration注解教程Spring 注入列表 XML 教程Spring BeanDefinitionBuilder教程Spring HikariCP 教程Java 教程

Spring @Configuration教程

原文: http://zetcode.com/spring/configuration/

Spring @Configuration注解教程展示了如何使用@Configuration注解配置 Spring 应用。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring @Configuration

@Configuration注解用于基于 Spring 注解的配置。 @Configuration是标记注解,指示类声明了一个或多个@Bean方法,并且可以由 Spring 容器处理以在运行时为这些 bean 生成 bean 定义和服务请求

Spring @Configuration示例

以下应用使用@Configuration来配置 Spring 应用。

pom.xml
src
└───src
    ├───main
    │   ├───java
    │   │   └───com
    │   │       └───zetcode
    │   │           │   Application.java
    │   │           └───config
    │   │                   AppConfig.java
    │   │                   H2Configurer.java
    │   └───resources
    │           application.properties
    │           logback.xml
    └───test
        └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>configurationex</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/application.properties

app.name=My application
app.db=H2

这里我们有一些应用属性。

com/zetcode/config/AppConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@ComponentScan(basePackages = "com.zetcode")
@PropertySource(value = "application.properties")
public class AppConfig {

    @Bean
    public H2Configurer databaseConfig() {
        return new H2Configurer();
    }
}

AppConfig是应用配置类。 它装饰有@Configuration注解,这是@Component的一种特殊形式。

@Configuration
@ComponentScan(basePackages = "com.zetcode")
@PropertySource(value = "application.properties")
public class AppConfig {

通过@ComponentScan启用组件扫描,并通过@PropertySource加载资源。

@Bean
public H2Configurer databaseConfig() {
    return new H2Configurer();
}

使用@Bean注解,我们创建了H2Configurer bean。

com/zetcode/config/H2Configurer.java

package com.zetcode.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class H2Configurer {

    private static final Logger logger = LoggerFactory.getLogger(H2Configurer.class);

    public H2Configurer() {

        logger.info("Configuring H2 database");
    }
}

H2Configurer仅记录一条消息。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.config.AppConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        var app = ctx.getBean(Application.class);

        app.run();

        ctx.close();
    }

    @Value("${app.name}")
    private String applicationName;

    @Value("${app.db}")
    private String database;

    private void run() {

        logger.info("Application name: {}", applicationName);
        logger.info("Database: {}", database);

    }
}

应用类显示应用属性。 这些属性通过@Value注入到属性中。

var ctx = new AnnotationConfigApplicationContext(AppConfig.class);

AppConfig被加载到应用上下文中。

$ mvn -q exec:java
20:07:39.769 INFO  com.zetcode.config.H2Configurer - Configuring H2 database 
20:07:39.801 INFO  com.zetcode.Application - Application name: My application 
20:07:39.816 INFO  com.zetcode.Application - Database: H2 

我们运行该应用。

在本教程中,我们使用@Configuration配置了一个 Spring 应用。

您可能也对这些相关教程感兴趣: Spring @Bean教程Spring @PropertySource教程Spring @ComponentScan教程Java 教程,或列出所有 Spring 教程

Spring C 命名空间教程

原文: http://zetcode.com/spring/cnamespace/

Spring 构造器名称空间教程展示了如何在 Spring 应用的基于构造器的注入中使用 C-命名空间。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring C 命名空间

Spring C-命名空间是 XML 快捷方式,并且替代了<bean/>标记的<constructor-arg/>子元素。 要启用 C 命名空间功能,我们需要将xmlns:c="http://www.springframework.org/schema/c"添加到 XML 文件中。 请注意,此命名空间没有单独的 XSD 文件。 因此,诸如 IntelliJ 之类的 IDE 无法识别它。

Spring C 命名空间示例

该应用包含两个User bean。 一个注入旧的<constructor-arg/>,另一个注入新的 C-命名空间属性。

src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           └───bean
│   │                   User.java
│   └───resources
│           logback.xml
│           my-beans.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>cnamespace</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/my-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:c="http://www.springframework.org/schema/c"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="user1" class="com.zetcode.bean.User">
        <constructor-arg name="name" value="John Doe"/>
        <constructor-arg name="occupation" value="gardener"/>
    </bean>

    <bean name="user2" class="com.zetcode.bean.User"
            c:name="Peter Smith" c:occupation="teacher"/>

</beans>

my-beans.xml文件声明了两个 bean:user1user2user1使用<constructor-arg/>注入其值,而user2使用c:namec:occupation属性。

com/zetcode/bean/User.java

package com.zetcode.bean;

public class User {

    private String name;
    private String occupation;

    public User(String name, String occupation) {
        this.name = name;
        this.occupation = occupation;
    }

    @Override
    public String toString() {

        final var sb = new StringBuilder("User{");
        sb.append("name='").append(name).append('\'');
        sb.append(", occupation='").append(occupation).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

这是由 Spring 容器管理的User类。 它必须包含一个构造器,因为我们在应用中使用了基于构造器的注入。

com/zetcode/Application.java

package com.zetcode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new GenericXmlApplicationContext("my-beans.xml");

        var u1 = ctx.getBean("user1");
        var u2 = ctx.getBean("user2");

        logger.info("{}", u1);
        logger.info("{}", u2);

        ctx.close();
    }
}

这是主要的应用类。 它检索两个 bean 并将它们打印到控制台。

$ mvn -q exec:java
16:40:39.632 INFO  com.zetcode.Application - User{name='John Doe', occupation='gardener'} 
16:40:39.632 INFO  com.zetcode.Application - User{name='Peter Smith', occupation='teacher'} 

我们运行该应用。

在本教程中,我们展示了如何在 C-命名空间中使用基于构造器的注入。

您可能也对这些相关教程感兴趣: Spring @Qualifier注解教程Spring 单例范围 beanSpring P-命名空间教程Spring BeanDefinitionBuilder教程Spring HikariCP 教程Java 教程

Spring P 命名空间教程

原文: http://zetcode.com/spring/pnamespace/

Spring 属性名称空间教程展示了如何在 Spring 应用的基于属性的注入中使用 P-命名空间。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring P 命名空间

Spring P-命名空间是 XML 快捷方式,并且替代了<bean/>标记的<property/>子元素。 要启用 P-命名空间功能,我们需要将xmlns:p="http://www.springframework.org/schema/p"添加到 XML 文件中。 请注意,此命名空间没有单独的 XSD 文件。 因此,诸如 IntelliJ 之类的 IDE 无法识别它。

Spring p 命名空间示例

该应用包含两个HelloMessage bean。 一个注入旧的<property/>,另一个注入新的 P-命名空间属性。

src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           └───bean
│   │                   HelloMessage.java
│   └───resources
│           logback.xml
│           my-beans.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>cnamespace</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/my-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="msg1" class="com.zetcode.bean.HelloMessage">
        <property name="message" value="How are you?"/>
    </bean>

    <bean name="msg2" class="com.zetcode.bean.HelloMessage" p:message="Hello there"/>

</beans>

my-beans.xml文件声明了两个 bean:msg1msg2msg1使用<property/>标签注入其值,而msg2使用p:message属性。

com/zetcode/bean/HelloMessage.java

package com.zetcode.bean;

public class HelloMessage {

    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {

        this.message = message;
    }
}

这是由 Spring 容器管理的HelloMessage类。 它必须包含一个设置器方法,因为我们在应用中使用了基于属性的注入。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.bean.HelloMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new GenericXmlApplicationContext("my-beans.xml");

        var msg1 = (HelloMessage) ctx.getBean("msg1");
        logger.info("{}", msg1.getMessage());

        var msg2 = (HelloMessage) ctx.getBean("msg2");
        logger.info("{}", msg2.getMessage());

        ctx.close();
    }
}

这是主要的应用类。 它检索两个HelloMessage bean,并将它们打印到控制台。

$ mvn -q exec:java
16:52:11.257 [main] INFO  com.zetcode.Application - How are you? 
16:52:11.273 [main] INFO  com.zetcode.Application - Hello there 

我们运行该应用。

在本教程中,我们展示了如何在 P 名称空间中使用基于属性的注入。

您可能也对这些相关教程感兴趣: Spring @Qualifier注解教程Spring 单例范围 beanSpring C-命名空间教程Spring BeanDefinitionBuilder教程Spring HikariCP 教程Java 教程

Spring bean 引用教程

原文: http://zetcode.com/spring/beanreference/

Spring bean 引用教程展示了如何在 Spring 应用的 XML 配置文件中引用 bean。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring ref属性

ref属性是<ref>标签的快捷方式,用于引用其他注入的 bean。

Spring bean 引用示例

该应用包含两个 bean:infoMessagemesageRenderermesageRenderer通过ref属性引用infoMessage

src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           ├───bean
│   │           │       IMessage.java
│   │           │       InfoMessage.java
│   │           └───service
│   │                   MessageRenderer.java
│   └───resources
│           logback.xml
│           my-beans.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>beanreference</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/my-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="infoMessage" class="com.zetcode.bean.InfoMessage"/>

    <bean name="messageRenderer" class="com.zetcode.service.MessageRenderer">
            <constructor-arg name="message" ref="infoMessage"/>
    </bean>

</beans>

my-beans.xml文件声明了两个 bean:infomessageRendererinfoMessage通过ref属性引用infoMessage。 Spring 通过构造器注入将infoMessage bean 注入message属性。

com/zetcode/bean/IMessage.java

package com.zetcode.bean;

public interface IMessage {

    String getMessage();
}

IMessage接口具有一个方法声明。

com/zetcode/bean/InfoMessage.java

package com.zetcode.bean;

public class InfoMessage implements IMessage {

    public String getMessage() {

        return "This is information message";
    }
}

InfoMessage bean 返回一条信息消息。

com/zetcode/service/MessageRenderer.java

package com.zetcode.service;

import com.zetcode.Application;
import com.zetcode.bean.IMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MessageRenderer {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    private IMessage message;

    public MessageRenderer(IMessage message) {
        this.message = message;
    }

    public void renderMessage() {

        logger.info("{}", message.getMessage());
    }
}

MessageRenderer呈现一条消息。 它期望注入一个 bean。 Spring 通过构造器注入将infoMessage bean 注入MessageRenderer

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.service.MessageRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new GenericXmlApplicationContext("my-beans.xml");
        var renderer =  (MessageRenderer) ctx.getBean("messageRenderer");

        renderer.renderMessage();

        ctx.close();
    }
}

这是主要的应用类。 它检索MessageRenderer bean 并调用其renderMessage()方法。

$ mvn -q exec:java
12:05:23.567 [com.zetcode.Application.main()] INFO  com.zetcode.Application - This is information message

我们运行该应用。

在本教程中,我们展示了如何使用 Spring 的 XML ref属性引用其他 bean。

您可能也对这些相关教程感兴趣: Spring @Qualifier注解教程Spring context:property-placeholder教程Spring 单例范围 beanSpring 注入列表 XML 教程Spring BeanDefinitionBuilder教程Spring HikariCP 教程Java 教程

Spring @Qualifier注解教程

原文: http://zetcode.com/spring/qualifier/

Spring @Qualifier注解教程显示了如何使用@Qualifier来区分 Spring 应用中的 bean。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring @Qualifier注解

如果 Spring 不能这样做,则@Qualifier注解有助于消除 Bean 引用的歧义。

Spring @Qualifier示例

该应用具有不同类型的消息 bean。 我们用@Qualifier区分它们。

src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           ├───bean
│   │           │       IMessage.java
│   │           │       Info.java
│   │           │       Warning.java
│   │           └───service
│   │                   MessageProducer.java
│   └───resources
│           logback.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>qualifierannotation</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/bean/IMessage.java

package com.zetcode.bean;

public interface IMessage {

    String getMessage();
}

IMessage接口具有一个方法声明。

com/zetcode/bean/Info.java

package com.zetcode.bean;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@Qualifier("info")
public class Info implements IMessage {

    @Override
    public String getMessage() {

        return "This is an information message";
    }
}

接口的第一个实现提供了一条信息消息。 @Qualifier用于标识 bean。

com/zetcode/bean/Warning.java

package com.zetcode.bean;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@Qualifier("warning")
public class Warning implements IMessage {

    public String getMessage() {

        return "This is a warning message";
    }
}

第二种实现给出警告消息。 它也以@Qualifier命名。

com/zetcode/service/MessageProducer.java

package com.zetcode.service;

import com.zetcode.bean.IMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class MessageProducer {

    private static final Logger logger = LoggerFactory.getLogger(MessageProducer.class);

    @Autowired
    @Qualifier("info")
    private IMessage infoMessage;

    @Autowired
    @Qualifier("warning")
    private IMessage warningMessage;

    public void produce() {

        logger.info("{}", infoMessage.getMessage());
        logger.warn("{}", warningMessage.getMessage());
    }
}

MessageProducer注入两个IMessage bean。 为了区分它们,我们使用@Qualifier注解。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.service.MessageProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = "com.zetcode.bean;com.zetcode.service")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        logger.info("Application starting");

        try (var ctx = new AnnotationConfigApplicationContext(Application.class)) {

            var messageProducer = (MessageProducer) ctx.getBean("messageProducer");
            messageProducer.produce();
        }
    }
}

这是主要的应用类。 它检索messageProducer bean 并调用其produce()方法。

$ mvn -q exec:java
10:50:03.309 [com.zetcode.Application.main()] INFO  com.zetcode.Application - Application starting
10:50:03.574 [com.zetcode.Application.main()] INFO  com.zetcode.service.MessageProducer - This is an information message
10:50:03.574 [com.zetcode.Application.main()] WARN  com.zetcode.service.MessageProducer - This is a warning message

我们运行该应用。

在本教程中,我们使用了 Spring 的@Qualifier注解。

您可能也对这些相关教程感兴趣: Spring @Bean教程Spring Boot @Qualifier注解Spring @ComponentScan教程Java 教程或列出所有 Spring 教程

Spring ClassPathResource教程

原文: http://zetcode.com/spring/classpathresource/

Spring ClassPathResource教程显示了如何在 Spring 应用中使用ClassPathResource读取资源。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring ClassPathResource

ClassPathResource允许从 Java 类路径获取资源。

Spring ClassPathResource示例

该应用从 Java 类路径中的文件读取文本数据。

src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           └───service
│   │                   ReadWordsService.java
│   └───resources
│           logback.xml
│           my-beans.xml
│           words.txt
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>classpathres</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/my-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="readWordsService" class="com.zetcode.service.ReadWordsService"/>

</beans>

my-beans.xml文件中,我们配置readWordsService bean。 它成为 Spring 托管的 bean。

resources/words.txt

sky
blue
mountain
fresh
cloud
rock
water
melon

resources目录包含在类路径中。 该应用从words.txt文件中读取单词。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/service/ReadWordsService.java

package com.zetcode.service;

import org.springframework.core.io.ClassPathResource;

import java.io.IOException;
import java.nio.file.Files;
import java.util.List;

public class ReadWordsService {

    public List<String> readWords() throws IOException {

        var res = new ClassPathResource("words.txt");

        var myFile = res.getFile();
        var lines = Files.readAllLines(myFile.toPath());

        return lines;
    }
}

ReadWordsService将单词读入列表,并将列表返回给客户端。

var res = new ClassPathResource("words.txt");

ClassPathResource用于定位文本文件。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.service.ReadWordsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.GenericXmlApplicationContext;
import java.io.IOException;

public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) throws IOException {

        var ctx = new GenericXmlApplicationContext("my-beans.xml");

        var wordsService = (ReadWordsService) ctx.getBean("readWordsService");
        var words = wordsService.readWords();

        words.forEach(word -> logger.info(word));

        ctx.close();
    }
}

这是主要的应用类。

var wordsService = (ReadWordsService) ctx.getBean("readWordsService");
var words = wordsService.readWords();

words.forEach(word -> logger.info(word));

我们从容器中检索readWordsService bean,并调用其readWords()方法。 文字将打印到控制台。

$ mvn -q exec:java
00:25:49.008 [com.zetcode.Application.main()] INFO  com.zetcode.Application - sky
00:25:49.008 [com.zetcode.Application.main()] INFO  com.zetcode.Application - blue
00:25:49.008 [com.zetcode.Application.main()] INFO  com.zetcode.Application - mountain
00:25:49.008 [com.zetcode.Application.main()] INFO  com.zetcode.Application - fresh
00:25:49.008 [com.zetcode.Application.main()] INFO  com.zetcode.Application - cloud
00:25:49.008 [com.zetcode.Application.main()] INFO  com.zetcode.Application - rock
00:25:49.008 [com.zetcode.Application.main()] INFO  com.zetcode.Application - water
00:25:49.008 [com.zetcode.Application.main()] INFO  com.zetcode.Application - melon

我们运行该应用。

在本教程中,我们使用了 Spring 的ClassPathResource

您可能也对这些相关教程感兴趣:经典 Spring 应用中的JdbcTemplateSpring 单例范围 beanSpring 注入列表 XML 教程Spring BeanDefinitionBuilder教程Spring HikariCP 教程Java 教程

Spring 原型作用域 bean

原文: http://zetcode.com/spring/prototypescope/

Spring Prototype 作用域 bean 教程展示了如何在 Spring 应用中使用 Prototype 作用域 bean。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring 原型 bean

原型 bean 每次针对该 bean 发出新请求时都会创建。

其他 bean 范围是:单例,请求,会话,全局会话和应用。

Spring 原型 bean 示例

该应用将创建两个原型范围内的 bean,并检查它们是否相同。 该应用是经典的 Spring 5 控制台应用。

────src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           │
│   │           └───bean
│   │                   Message.java
│   │
│   └───resources
│           logback.xml
│           my-beans.xml
│
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>prototypescopedbean</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/my-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.zetcode"/>

</beans>

通过context:component-scan标签,我们指示 Spring 在com.zetcode包中查找 bean。 它将找到我们唯一的Message bean,并用@Component装饰。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/bean/Message.java

package com.zetcode.bean;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class Message {

    private String message;

    public String getMessage() {

        return message;
    }
}

Message是由 Spring 容器管理的 Spring bean。 它具有原型范围。

@Component
@Scope("prototype")
public class Message {

@Scope("prototype")将 bean 的范围设置为原型。 默认值为单例。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.bean.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new GenericXmlApplicationContext("my-beans.xml");

        var beanA = ctx.getBean(Message.class);
        var beanB = ctx.getBean(Message.class);

        if (beanA.equals(beanB)) {

            logger.info("The beans are identical");
        } else {

            logger.info("The beans are not identical");
        }

	ctx.close();
    }
}

这是主要的应用类。

var ctx = new GenericXmlApplicationContext("my-beans.xml");

我们使用GenericXmlApplicationContextmy-beans.xml文件创建 Spring 应用上下文。

var bean1 = ctx.getBean(Message.class);
var bean2 = ctx.getBean(Message.class);

app.run(bean1, bean2);

我们从应用上下文中获得两个 bean,并将它们传递给run()方法进行比较。

logger.info(a.getMessage());

我们从 bean 中读取消息。

if (a.equals(b)) {

    logger.info("The beans are the same");
} else {

    logger.info("The beans are not the same");
}

我们测试两个豆是否相同。

$ mvn -q exec:java
21:26:03.089 [com.zetcode.Application.main()] INFO  com.zetcode.Application - The beans are not identical

我们运行该应用。 将Message bean 的范围更改为单例并比较结果。

在本教程中,我们使用了原型 Spring bean。

您可能也对这些相关教程感兴趣:经典的 Spring 应用中的 JdbcTemplateSpring 单例范围 beanSpring ClassPathResource教程Spring 注入列表 XML 教程Spring BeanDefinitionBuilder教程Spring HikariCP 教程Java 教程

Spring @Autowired教程

原文: http://zetcode.com/spring/autowired/

Spring @Autowired教程展示了如何使用@Autowired注解在 Spring 应用中注入依赖项。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring @Autowired

@Autowired注解标记将由 Spring 的依赖项注入工具自动装配的构造器,字段,设置器方法或配置方法。 它是 JSR-330 @Inject注解的替代方法。

Spring @Autowired示例

应用使用@Autowired注入依赖项。 依赖关系是一个返回单词的服务对象。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           └───service
│   │                   WordService.java
│   └───resources
│           logback.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springautowired</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>      

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/service/WordService.java

package com.zetcode.service;

import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Random;

@Service
public class WordService {

    private final List<String> words = List.of("pen", "sky",
            "rock", "forest", "falcon", "eagle");

    public List<String> all() {

        return words;
    }

    public String randomWord() {

        return words.get(new Random().nextInt(words.size()));
    }
}

WordService类带有@Service注解。 Spring 在组件扫描的帮助下将其注册为托管 Bean。 稍后将此服务对象与@Autowired一起注入Application中。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.service.WordService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

@Component
@ComponentScan(basePackages="com.zetcode")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    @Autowired
    private WordService wordService;

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(Application.class);

        var bean = ctx.getBean(Application.class);
        bean.run();

        ctx.close();
    }

    public void run() {

        logger.info("{}", wordService.randomWord());
        logger.info("{}", wordService.randomWord());

        var words = wordService.all();
        words.stream().forEach(word -> logger.info("{}", word));
    }
}

使用WordService使用输出字注解应用。 服务依赖项与@Autowired一起注入Application中。

@Autowired
private WordService wordService;

这称为场注入。

注意:虽然字段注入简短而有趣,但通常建议使用构造器注入或设置器注入。

$ mvn -q exec:java
17:15:34.504 INFO  com.zetcode.Application - falcon
17:15:34.507 INFO  com.zetcode.Application - eagle
17:15:34.508 INFO  com.zetcode.Application - pen
17:15:34.508 INFO  com.zetcode.Application - sky
17:15:34.509 INFO  com.zetcode.Application - rock
17:15:34.509 INFO  com.zetcode.Application - forest
17:15:34.510 INFO  com.zetcode.Application - falcon
17:15:34.510 INFO  com.zetcode.Application - eagle

我们运行该应用。

在本教程中,我们使用@Autowired在 Spring 中注入了依赖项。

您可能也对这些相关教程感兴趣: Spring @Bean注解教程Spring @ComponentScan教程Java 教程或列出所有 Spring 教程

Spring List XML 注入教程

原文: http://zetcode.com/spring/injectlistxml/

Spring 注入列表 XML 教程展示了如何在 XML 配置中将列表注入到应用上下文中。

Spring 是用于创建企业应用的流行 Java 应用框架。

util 模式

util XML 模式处理常见的工具配置问题,例如配置集合或引用常量。

Spring 注入列表示例

该应用从 Spring XML 配置注入一个 List 集合。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>injectlistex</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

src/main/resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

src/main/resources/my-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/util
            http://www.springframework.org/schema/util/spring-util.xsd">

    <context:component-scan base-package="com.zetcode"/>

    <util:list id="myColours" value-type="java.lang.String">
        <value>red</value>
        <value>green</value>
        <value>blue</value>
        <value>yellow</value>
        <value>brown</value>
        <value>orange</value>
    </util:list>
</beans>

my-beans.xml配置文件中,我们定义了颜色列表。 列表类型为java.util.String,并使用value标签指定值。 我们需要导入适当的架构定义。

src/main/java/com/zetcode/Application.java

package com.zetcode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.GenericXmlApplicationContext;

import java.util.List;

public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new GenericXmlApplicationContext("my-beans.xml");
        var colours = (List<String>) ctx.getBean("myColours");

        logger.info(colours.toString());

        ctx.close();
    }
}

Application类中,我们使用getBean()检索 bean 列表并将其记录到控制台。

$ mvn -q exec:java
21:28:19.770 [com.zetcode.Application.main()] INFO  com.zetcode.Application - [red, green, blue, yellow, brown, orange]    

我们运行该应用。

在本教程中,我们展示了如何使用 XML 配置将值列表注入到应用中。

您可能对以下相关教程感兴趣:经典 Spring 应用中的 JdbcTemplateSpring 单例范围 beanSpring BeanDefinitionBuilder 教程Spring HikariCP 教程Java 教程

Spring 概要文件 XML 教程

原文: http://zetcode.com/spring/profilexml/

Spring 概要文件 XML 教程显示了如何为 Spring 应用配置 XML 概要文件。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring 简介

概要文件是为特定环境(例如开发或生产)声明的一组命名 Bean。 可以使用 XML 或使用注解来配置配置文件。

Spring 配置文件示例

该应用定义了两个配置文件:生产和开发。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │               Application.java
│   └───resources
│           database-dev.properties
│           database-prod.properties
│           logback.xml
└───test
    └───java

这是项目结构。 我们有两个属性文件:database-dev.propertiesdatabase-prod.properties

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>profileex</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>      

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-version}</version>
        </dependency>        

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-contextspring-jdbc和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/database-dev.properties

db.url=jdbc:h2:mem:testdb
db.username=testuser
db.password=s$cret

这些是开发属性。

resources/database-prod.properties

db.url=jdbc:postgresql://localhost/mydb
db.username=user7
db.password=s$cret

这些是生产属性。

resources/my-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="classpath:database-${spring.profiles.active}.properties"/>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <property name="url" value="${db.url}"/>
        <property name="username" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
    </bean>

</beans>

my-beans.xml包含dataSource bean。 <context:property-placeholder>标签基于活动的 Spring 配置文件为数据源配置属性。

com/zetcode/Application.java

package com.zetcode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;

public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        System.setProperty("spring.profiles.active", "prod");

        var ctx = new GenericXmlApplicationContext("my-beans.xml");

        var dataSource = (SimpleDriverDataSource) ctx.getBean("dataSource");

        logger.info("Url: {}", dataSource.getUrl());
        logger.info("User name: {}", dataSource.getUsername());
        logger.info("Password: {}", dataSource.getPassword());

        ctx.close();
    }
}

该应用检索dataSource bean 并打印其属性。 激活属性是通过System.setProperty()方法设置的。 另外,我们可以将属性设置为 VM 变量-Dspring.profiles.active=prod或在 IDE 设置中。

$ mvn -q -Dspring.profiles.active=dev exec:java
20:30:45.832 INFO  com.zetcode.Application - Url: jdbc:h2:mem:testdb
20:30:45.832 INFO  com.zetcode.Application - User name: testuser
20:30:45.832 INFO  com.zetcode.Application - Password: s$cret

我们在命令行上设置了配置文件的情况下运行应用

在本教程中,我们为 Spring 应用创建了开发和生产数据。

您可能也对这些相关教程感兴趣: Spring @Bean注解教程Spring 单例范围 beanSpring @ComponentScan教程Spring 注入列表 XML 教程Spring BeanDefinitionBuilder教程Spring HikariCP 教程Java 教程

Spring BeanDefinitionBuilder教程

原文: http://zetcode.com/spring/beandefinitionbuilder/

Spring BeanDefinitionBuilder教程展示了如何使用BeanDefinitionBuilder以编程方式创建新的 Spring Bean。

Spring 是用于创建企业应用的流行 Java 应用框架。

BeanDefinitionBuilder

BeanDefinitionBuilder用于以编程方式创建新的 Spring bean。 它利用了构建器模式。

Spring BeanDefinitionBuilder示例

该应用创建一个简单的字符串 bean。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>beanbuilderex</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

src/main/resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

src/main/java/com/zetcode/Application.java

package com.zetcode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = "com.zetcode")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(Application.class);

        var beanFactory = (BeanDefinitionRegistry) ctx.getBeanFactory();

        beanFactory.registerBeanDefinition("myBean",
                BeanDefinitionBuilder.genericBeanDefinition(String.class)
                        .addConstructorArgValue("This is my bean")
                        .setScope("prototype")
                        .getBeanDefinition()
        );

        logger.info("{}", ctx.getBean("myBean"));

        ctx.close();
    }
}

该示例使用BeanDefinitionBuilder创建一个类型为String的简单 bean。

var beanFactory = (BeanDefinitionRegistry) ctx.getBeanFactory();

使用getBeanFactory()从应用上下文中检索 bean 工厂。

beanFactory.registerBeanDefinition("myBean",
    BeanDefinitionBuilder.genericBeanDefinition(String.class)
            .addConstructorArgValue("This is my bean")
            .setScope("prototype")
            .getBeanDefinition()
);

我们向registerBeanDefinition()注册了一个新 bean。

logger.info("{}", ctx.getBean("myBean"));

我们使用getBean()从应用上下文中获取 bean 并将其记录下来。

$ mvn -q exec:java
20:51:05.970 [com.zetcode.Application.main()] INFO com.zetcode.Application - This is my bean    

我们运行该应用。

在本教程中,我们使用BeanDefinitionBuilder以编程方式注册了一个新的 Spring bean。

您可能也对这些相关教程感兴趣: Spring 注入列表 XML 教程Spring BeanFactory教程经典 Spring 应用中的JdbcTemplateSpring 单例范围 beanSpring HikariCP 教程Java 教程

Spring 单例作用域 bean

原文: http://zetcode.com/spring/单例scope/

Spring 单例作用域 bean 教程展示了如何在 Spring 应用中使用单例作用域 bean。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring 单例 bean

单例 bean 是在创建 Spring 容器时创建的,在销毁容器时会被销毁。 单例 bean 是共享的; 每个 Spring 容器仅创建一个单例 bean 实例。 单例范围是 Spring bean 的默认范围。

其他 bean 范围是:原型,请求,会话,全局会话和应用。

Spring 单例 bean 示例

该应用创建两个单例作用域 Bean,并检查它们是否相同。 该应用是经典的 Spring 5 控制台应用。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>scopesingletonex</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们具有基本的 Spring 依赖项spring-corespring-context和日志记录logback-classic依赖项。

exec-maven-plugin用于在命令行上从 Maven 执行 Spring 应用。

resources/my.properties

myapp.name=ScopeSingleton
myapp.author=Jan Bodnar

my.properties文件中有两个基本属性。 它们正在Message bean 中使用。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/bean/Message.java

package com.zetcode.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("单例") // change to prototype
@PropertySource("classpath:my.properties")
public class Message {

    @Value("${myapp.name}")
    private String name;

    @Value("${myapp.author}")
    private String author;

    public String getMessage() {

        return String.format("Application %s was created by %s", name, author);
    }
}

Message是由 Spring 容器管理的 Spring bean。 它具有单例范围。

@Component
@Scope("单例") // change to prototype
@PropertySource("classpath:my.properties")
public class Message {

不需要@Scope("单例")注解; 如果未指定,默认范围是单例。 使用@PropertySource注解,我们指定属性文件。 稍后使用@Value读取属性。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.bean.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = "com.zetcode")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(Application.class);

        var app = ctx.getBean(Application.class);

        var bean1 = ctx.getBean(Message.class);
        var bean2 = ctx.getBean(Message.class);

        app.run(bean1, bean2);

        ctx.close();
    }

    public void run(Message a, Message b) {

        logger.info("running Application");

        logger.info(a.getMessage());

        if (a.equals(b)) {

            logger.info("The beans are the same");
        } else {

            logger.info("The beans are not the same");
        }
    }
}

这是主要的应用类。

var bean1 = ctx.getBean(Message.class);
var bean2 = ctx.getBean(Message.class);

app.run(bean1, bean2);

我们从应用上下文中获取这两个 bean,并将它们传递给run()方法进行比较。

logger.info(a.getMessage());

我们从 bean 中读取消息。

if (a.equals(b)) {

    logger.info("The beans are the same");
} else {

    logger.info("The beans are not the same");
}

我们测试两个 bean 是否相同。

$ mvn -q exec:java
21:28:35.573 [com.zetcode.Application.main()] INFO  com.zetcode.Application - running Application
21:28:35.575 [com.zetcode.Application.main()] INFO  com.zetcode.Application - Application ScopeSingleton was created by Jan Bodnar
21:28:35.576 [com.zetcode.Application.main()] INFO  com.zetcode.Application - The beans are the same

我们运行该应用。 将Message bean 的范围更改为原型并比较结果。

在本教程中,我们使用了单例 Spring bean。

您可能也对这些相关教程感兴趣: Spring 原型作用域 beanSpring 应用的JdbcTemplateSpring 注入列表 XML 教程Spring 中BeanDefinitionBuilder教程Spring HikariCP 教程Java 教程

独立的 Spring 应用

原文: http://zetcode.com/articles/standalonespring/

在本教程中,我们将创建两个简单的 Java Spring 独立应用。 我们将使用 NetBeans 来构建应用。

Spring 是流行的 Java 应用框架。 它提供了用于企业应用编程的各种库和工具。 这也是一个非常好的集成系统,可以帮助将各种企业组件粘合在一起。

Spring ApplicationContext是用于为应用提供配置的中央接口。 ClassPathXmlApplicationContextApplicationContext的实现,该实现从位于类路径上的 XML 文件加载配置定义。 AnnotationConfigApplicationContext创建一个新的应用上下文,该上下文从给定的带注解的类派生 Bean 定义。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zetcode</groupId>
    <artifactId>SpringStandaloneEx2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring-version>4.3.0.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

</project>

我们将 Maven 构建文件用于两个应用。 它包含必要的 Spring 依赖关系。

具有ClassPathXmlApplicationContext的 Spring 应用

我们在 NetBeans IDE 中创建一个新的 Maven Java SE 应用。

Spring project structure in NetBeans

图:NetBeans 中的 Spring 项目结构

在项目中,有四个文件:Message.javaApplication.javamy-beans.xmlpom.xml

Message.java

package com.zetcode.bean;

public class Message {

   private String message;

   public void setMessage(String message){

      this.message = message;
   }

   public String getMessage(){

      return message;
   }
}

Message是我们的应用中使用的简单 Java Bean。

my-beans.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="mymessage" class="com.zetcode.bean.Message">
       <property name="message" value="Hello there!"/>
   </bean>

</beans>

我们将Message类制成 Spring Bean; 现在,它由 Spring 容器管理。 我们还为message属性提供了一个值。 my-beans.xml位于src/main/resources子目录中。

Application.java

package com.zetcode.main;

import com.zetcode.bean.Message;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Application {

   public static void main(String[] args) {

      ApplicationContext context = 
             new ClassPathXmlApplicationContext("my-beans.xml");

      Message obj = (Message) context.getBean("mymessage");

      String msg = obj.getMessage();
      System.out.println(msg);
   }
}

Application设置 Spring 应用。

ApplicationContext context = 
        new ClassPathXmlApplicationContext("my-beans.xml");

my-beans.xml文件,创建ApplicationContext

Message obj = (Message) context.getBean("mymessage");

从应用上下文中,我们检索Message bean。

String msg = obj.getMessage();
System.out.println(msg);

我们调用 bean 的getMessage()方法,并将消息打印到控制台。

Hello there!

这是应用的输出。

具有AnnotationConfigApplicationContext的 Spring 应用

在第二个示例中,我们将使用AnnotationConfigApplicationContext创建 Spring ApplicationContext

Message.java

package com.zetcode.bean;

import org.springframework.stereotype.Component;

@Component
public class Message {

   private String message = "Hello there!";

   public void setMessage(String message){

      this.message  = message;
   }

   public String getMessage(){

      return message;
   }
}

Message bean 用@Component注解修饰。 此类由 Spring 自动检测。

Application.java

package com.zetcode.main;

import com.zetcode.bean.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = "com.zetcode")
public class Application {

    public static void main(String[] args) {

        ApplicationContext context
                = new AnnotationConfigApplicationContext(Application.class);

        Application p = context.getBean(Application.class);
        p.start();
    }

    @Autowired
    private Message message;
    private void start() {
        System.out.println("Message: " + message.getMessage());
    }
}

这是主要的Application类。

@ComponentScan(basePackages = "com.zetcode")

使用@ComponentScan注解,我们告诉 Spring 在哪里寻找组件。

ApplicationContext context
        = new AnnotationConfigApplicationContext(Application.class);

ApplicationContext由注解创建。

@Autowired
private Message message;
private void start() {
    System.out.println("Message: " + message.getMessage());
}

使用@Autowired注解,Message bean 被注入到message变量中。

在本教程中,我们创建了两个独立的 Spring 应用。 第一个使用 XML 文件,第二个使用注解。 您可能也对相关教程感兴趣: Spring Web 应用简介Spring Boot 优先 Web 应用Java 教程

经典 Spring 应用中的JdbcTemplate

原文: http://zetcode.com/articles/springjdbctemplate/

在本教程中,我们展示了如何使用JdbcTemplate创建经典的 Spring 应用。 该应用连接到 MySQL 数据库,并使用JdbcTemplate发出 SQL 语句。

Spring 是用于在 Java 中开发企业应用的流行 Java 应用框架。 这也是一个非常好的集成系统,可以帮助将各种企业组件粘合在一起。

JdbcTemplate是一个库,可帮助程序员创建与关系数据库和 JDBC 一起使用的应用。 它处理许多繁琐且容易出错的底层细节,例如处理事务,清理资源以及正确处理异常。 JdbcTemplate在 Spring 的spring-jdbc模块中提供。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zetcode</groupId>
    <artifactId>SpringJdbcTemplateEx</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring-version>4.3.0.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>        

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>    

</project>

在 Maven 构建文件中,我们提供了 Spring 应用核心,JdbcTemplate库和 MySQL 驱动程序的依赖关系。

Friend.java

package com.zetcode.bean;

public class Friend {

    private int id;
    private String name;
    private int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Friend{" + "id=" + id + ", name=" + 
                name + ", age=" + age + '}';
    }
}

这是一个Friend类。 数据库表中的一行将映射到此类。

my-beans.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/testdb?useSSL=false"/>
        <property name="username" value="testuser"/>
        <property name="password" value="test623"/>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>    

</beans>

在我们称为my-beans.xml的应用上下文 XML 文件中,我们定义了两个 bean:数据源 bean 和jdbcTemplate bean。 数据源 bean 包含数据源属性。 jdbcTemplate通过ref属性引用dataSource bean。 my-beans.xml位于src/main/resources子目录中。

SpringJdbcTemplateEx.java

package com.zetcode;

import com.zetcode.bean.Friend;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

public class SpringJdbcTemplateEx {

    public static void main(String[] args) {

        ApplicationContext ctx
                = new ClassPathXmlApplicationContext("my-beans.xml");

        JdbcTemplate jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate");

        jdbcTemplate.execute("DROP TABLE IF EXISTS Friends");
        jdbcTemplate.execute("CREATE TABLE Friends(Id INT, Name VARCHAR(30), "
                + "Age INT)");
        jdbcTemplate.update("INSERT INTO Friends VALUES(1, 'Paul', 27)");
        jdbcTemplate.update("INSERT INTO Friends VALUES(2, 'Monika', 34)");
        jdbcTemplate.update("INSERT INTO Friends VALUES(3, 'Peter', 20)");
        jdbcTemplate.update("INSERT INTO Friends VALUES(4, 'Lucy', 45)");
        jdbcTemplate.update("INSERT INTO Friends VALUES(5, 'Roman', 57)");

        int id = 1;
        String sql = "SELECT * FROM Friends WHERE Id=?";

        Friend f = (Friend) jdbcTemplate.queryForObject(sql, new Object[]{id},
                new BeanPropertyRowMapper(Friend.class));

        System.out.println(f);

        List<Friend> allFriends = jdbcTemplate.query("SELECT * FROM Friends",
                new BeanPropertyRowMapper(Friend.class));

        allFriends.stream().forEach(System.out::println);
    }
}

SpringJdbcTemplateEx设置 Spring 应用。

ApplicationContext context = 
        new ClassPathXmlApplicationContext("my-beans.xml");

my-beans.xml文件,创建ApplicationContext。 Spring ApplicationContext是为应用提供配置的中央接口。 ClassPathXmlApplicationContextApplicationContext的实现,可从位于类路径上的 XML 文件加载配置定义。

JdbcTemplate jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate");

从应用上下文中,我们获得jdbcTemplate bean。

jdbcTemplate.execute("DROP TABLE IF EXISTS Friends");
jdbcTemplate.execute("CREATE TABLE Friends(Id INT, Name VARCHAR(30), "
        + "Age INT)");

使用JdbcTemplateexecute()方法,我们创建了Friends表。

jdbcTemplate.update("INSERT INTO Friends VALUES(1, 'Paul', 27)");

我们使用JdbcTemplateupdate()方法插入一条语句。

int id = 1;
String sql = "SELECT * FROM Friends WHERE Id=?";

在此 SQL 语句中,我们选择一个由其 ID 标识的朋友。

Friend f = (Friend) jdbcTemplate.queryForObject(sql, new Object[]{id},
        new BeanPropertyRowMapper(Friend.class));

JdbcTemplatequeryForObject()方法执行 SQL 查询并返回结果对象。 使用BeanPropertyRowMapper将结果对象映射到Friend对象。

List<Friend> allFriends = jdbcTemplate.query("SELECT * FROM Friends",
        new BeanPropertyRowMapper(Friend.class));

allFriends.stream().forEach(System.out::println);

使用JdbcTemplatequery()方法,我们检索所有朋友并将其打印到控制台。

Friend{id=1, name=Paul, age=27}
Friend{id=1, name=Paul, age=27}
Friend{id=2, name=Monika, age=34}
Friend{id=3, name=Peter, age=20}
Friend{id=4, name=Lucy, age=45}
Friend{id=5, name=Roman, age=57}

这是示例的输出。

在本教程中,我们创建了一个经典的 Spring 应用,该应用使用JdbcTemplate发出了 SQL 语句。 Spring 应用是用 XML 配置的。 您可能也对这些相关教程感兴趣: JdbcTemplate教程Spring Web 应用简介Spring Boot 第一个 Web 应用Java 教程

Spring EmbeddedDatabaseBuilder教程

原文: http://zetcode.com/spring/embeddeddatabasebuilder/

Spring EmbeddedDatabaseBuilder教程展示了如何使用EmbeddedDatabaseBuilder在 Spring 应用中创建 H2 嵌入式数据库。

Spring 是流行的 Java 应用框架。

EmbeddedDatabaseBuilder

EmbeddedDatabaseBuilder是一个 Spring 构建器,它提供方便的 API 在 Spring 应用中创建嵌入式数据库。

Spring EmbeddedDatabaseBuilder示例

以下示例使用EmbeddedDatabaseBuilder构建嵌入式 H2 数据库。 我们使用 Spring JdbcTemplate与数据库进行交互。

pom.xml
src    
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           ├───config
│   │           │       DBConfig.java
│   │           └───model
│   │                   Car.java
│   └───resources
│       │   logback.xml
│       └───db
│               create-db.sql
│               insert-data.sql
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>embeddeddatabasebuilderex</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.197</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

这是我们 Spring 应用的 Maven 构建文件。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

这是 Logback 配置文件。

EmbeddedDatabaseBuilder将使用以下两个 SQL 脚本来创建cars表并将数据插入其中。

resources/db/schema.sql

CREATE TABLE cars(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(150), price INT);

schema.sql创建数据库表。

resources/db/data.sql

INSERT INTO cars(name, price) VALUES('Audi', 52642);
INSERT INTO cars(name, price) VALUES('Mercedes', 57127);
INSERT INTO cars(name, price) VALUES('Skoda', 9000);
INSERT INTO cars(name, price) VALUES('Volvo', 29000);
INSERT INTO cars(name, price) VALUES('Bentley', 350000);
INSERT INTO cars(name, price) VALUES('Citroen', 21000);
INSERT INTO cars(name, price) VALUES('Hummer', 41400);
INSERT INTO cars(name, price) VALUES('Volkswagen', 21600);

data.sql将数据插入表中。

com/zetcode/model/Car.java

package com.zetcode.model;

import java.util.Objects;

public class Car {

    private Long id;
    private String name;
    private int price;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Car car = (Car) o;
        return price == car.price &&
                Objects.equals(id, car.id) &&
                Objects.equals(name, car.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, price);
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Car{");
        sb.append("id=").append(id);
        sb.append(", name='").append(name).append('\'');
        sb.append(", price=").append(price);
        sb.append('}');
        return sb.toString();
    }
}

这是一个Car类。

com/zetcode/config/DBConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;

import javax.sql.DataSource;

@Configuration
public class DBConfig  {

    @Bean
    public DataSource dataSource() {

        var builder = new EmbeddedDatabaseBuilder();
        var db = builder
                .setType(EmbeddedDatabaseType.H2) // HSQL or DERBY
                .addScript("db/schema.sql")
                .addScript("db/data.sql")
                .build();
        return db;
    }

    @Bean
    public JdbcTemplate createJdbcTeamplate() {

        var template = new JdbcTemplate();
        template.setDataSource(dataSource());

        return template;
    }
}

DBConfig使用EmbeddedDatabaseBuilder创建嵌入式 H2 数据库。 我们还创建了一个JdbcTemplate bean。

@Bean
public DataSource dataSource() {

    var builder = new EmbeddedDatabaseBuilder();
    var db = builder
            .setType(EmbeddedDatabaseType.H2) // HSQL or DERBY
            .addScript("db/schema.sql")
            .addScript("db/data.sql")
            .build();
    return db;
}

该方法使用EmbeddedDatabaseBuilderbuild()方法创建数据源。 我们使用setType()指定数据库类型,并使用addScript()方法添加 SQL 脚本。

@Bean
public JdbcTemplate createJdbcTeamplate() {

    var template = new JdbcTemplate();
    template.setDataSource(dataSource());

    return template;
}

此方法生成一个新的JdbcTemplate。 我们使用setDataSource()将生成的数据源设置为模板。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.model.Car;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

@ComponentScan(basePackages = "com.zetcode")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(Application.class);
        var app = ctx.getBean(Application.class);

        app.run();

        ctx.close();
    }

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private void run() {

        var sql = "SELECT * FROM cars";

        var cars = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Car.class));

        cars.forEach(car -> logger.info("{}", car));
    }
}

在应用中,我们执行查询以查找所有汽车。

@Autowired
private JdbcTemplate jdbcTemplate;

注入了JdbcTemplate bean。

var cars = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Car.class));

使用JdbcTemplatequery()方法执行 SQL 查询。

cars.forEach(car -> logger.info("{}", car));

检索到的汽车将写入控制台。

$ mvn -q exec:java
19:13:35.753 INFO  com.zetcode.Application - Car{id=1, name='Audi', price=52642}
19:13:35.768 INFO  com.zetcode.Application - Car{id=2, name='Mercedes', price=57127}
19:13:35.768 INFO  com.zetcode.Application - Car{id=3, name='Skoda', price=9000}
19:13:35.768 INFO  com.zetcode.Application - Car{id=4, name='Volvo', price=29000}
19:13:35.768 INFO  com.zetcode.Application - Car{id=5, name='Bentley', price=350000}
19:13:35.768 INFO  com.zetcode.Application - Car{id=6, name='Citroen', price=21000}
19:13:35.768 INFO  com.zetcode.Application - Car{id=7, name='Hummer', price=41400}
19:13:35.768 INFO  com.zetcode.Application - Car{id=8, name='Volkswagen', price=21600}

我们运行该应用。

在本教程中,我们使用EmbeddedDatabaseBuilder在 Spring 应用中创建嵌入式 H2 数据库。

您可能也对相关教程感兴趣: JdbcTemplate教程Spring @ComponentScan教程Java 教程

Spring HikariCP 教程

原文: http://zetcode.com/articles/springhikaricp/

在本教程中,我们将展示如何在经典的 Spring 应用中使用 HikariCP 连接池。 在应用中,我们使用 Spring JdbcTemplate连接到 MySQL 数据库。 我们使用 FreeMarker 作为模板引擎。 该应用已部署在 Tomcat 服务器上。

Spring 是用于在 Java 中开发企业应用的流行 Java 应用框架。 这也是一个非常好的集成系统,可以帮助将各种企业组件粘合在一起。

HikariCP 是可靠的高性能 JDBC 连接池。 连接池是数据库系统维护的数据库连接的高速缓存,用于在需要将来对数据库的请求时重用连接。 使用连接池,我们可以大大减少整体资源的使用。

JdbcTemplate是一个 Spring 库,可以帮助程序员创建与关系数据库和 JDBC 一起使用的应用。 它会处理许多繁琐且容易出错的底层细节,例如处理事务,清理资源以及正确处理异常。 JdbcTemplate在 Spring 的spring-jdbc模块中提供。

cars.sql

-- SQL for the Cars table

START TRANSACTION;
DROP TABLE IF EXISTS Cars;

CREATE TABLE Cars(Id INTEGER PRIMARY KEY, Name VARCHAR(50), Price INTEGER);
INSERT INTO Cars VALUES(1, 'Audi', 52642);
INSERT INTO Cars VALUES(2, 'Mercedes', 57127);
INSERT INTO Cars VALUES(3, 'Skoda', 9000);
INSERT INTO Cars VALUES(4, 'Volvo', 29000);
INSERT INTO Cars VALUES(5, 'Bentley', 350000);
INSERT INTO Cars VALUES(6, 'Citroen', 21000);
INSERT INTO Cars VALUES(7, 'Hummer', 41400);
INSERT INTO Cars VALUES(8, 'Volkswagen', 21600);
COMMIT;

在代码示例中,我们使用此表。

mysql> source cars.sql

使用mysql命令行工具及其source命令,创建Cars表。 MySQL 教程提供了有关如何设置和使用 MySQL 数据库的更多信息。

├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── bean
    │   │           │   └── Car.java
    │   │           ├── service
    │   │           │   └── CarService.java
    │   │           └── web
    │   │              └── MyController.java
    │   ├── resources
    │   │   └── application-context.xml
    │   └── webapp
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    │           ├── spring-servlet.xml
    │           ├── views
    │           │   ├── allCars.ftl
    │           │   └── index.ftl
    │           └── web.xml
    └── test
        └── java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>SpringJdbcTemplateWebEx</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>SpringJdbcTemplateWebEx</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>        
        <spring-version>4.3.7.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>              

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.25-incubating</version>
        </dependency>   

         <!--Needed for freemarker FreeMarkerConfigurer--> 
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring-version}</version>
        </dependency>                

        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>2.5.1</version>
        </dependency>      

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.22</version>
        </dependency>          

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring-version}</version>
        </dependency>         

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-version}</version>
        </dependency>              

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

在此 Maven 构建文件中,我们为 Spring 应用的核心,HikariCP 连接池,FreeMarker 模板引擎,JdbcTemplate库和 MySQL 驱动程序提供依赖关系。

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                 http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>    

    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

web.xml文件中,我们设置了 Spring DispatcherServletDispatcherServlet是 HTTP 请求处理器的中央调度器。

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/SpringJdbcTemplateWebEx">

    <Resource name="jdbc/myDs" auth="Container"
              factory="com.zaxxer.hikari.HikariJNDIFactory"
              dataSourceClassName="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
              dataSource.url="jdbc:mysql://localhost/testdb?useSSL=false"
              type="javax.sql.DataSource"
              minimumIdle="5" 
              maximumPoolSize="10"
              connectionTimeout="300000"
              database="testdb"
              server="localhost"
              dataSource.user="testuser"
              dataSource.password="test623"
              dataSource.cachePrepStmts="true"
              dataSource.prepStmtCacheSize="250"
              dataSource.prepStmtCacheSqlLimit="2048"
              closeMethod="close"
    />

</Context>

Tomcat 的context.xml文件包含数据源定义。 数据源使用 HikariCP 连接池。

spring-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.zetcode" />
    <import resource="classpath:application-context.xml" />

    <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <property name="templateLoaderPath" value="/WEB-INF/views/"/>
    </bean>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
        <property name="cache" value="true"/>
        <property name="prefix" value=""/>
        <property name="suffix" value=".ftl"/>
    </bean>   

</beans>

在 spring servlet 上下文 XML 文件中,我们定义了两个 bean:freemarkerConfigviewResolver。 这些是 FreeMarker 的配置 bean。 spring-servlet.xml位于WEB-INF子目录中。

<context:component-scan base-package="com.zetcode" />

我们启用com.zetcode封装的组件扫描。

<import resource="classpath:application-context.xml" />

我们导入另一个上下文文件,称为application-context.xml。 它位于src/main/resources目录中的类路径上。

application-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                          http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/jdbc/myDs"/>
    </bean>    

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>    

</beans>

application-context.xml中,我们定义了两个 bean:dataSourcejdbcTemplate

Car.java

package com.zetcode.bean;

public class Car {

    private int Id;
    private String Name;
    private int Price;

    public int getId() {
        return Id;
    }

    public void setId(int Id) {
        this.Id = Id;
    }

    public String getName() {
        return Name;
    }

    public void setName(String Name) {
        this.Name = Name;
    }

    public int getPrice() {
        return Price;
    }

    public void setPrice(int Price) {
        this.Price = Price;
    }

    @Override
    public String toString() {
        return "Car{" + "Id=" + Id + ", Name=" + 
                Name + ", Price=" + Price + '}';
    }
}

这是一个Car类。 数据库表中的一行将映射到此类。

CarService.java

package com.zetcode.service;

import com.zetcode.bean.Car;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class CarService {

    @Autowired
    public JdbcTemplate jdbcTemplate;

    public List<Car> getAllCars() {

        String sql = "SELECT * FROM Cars";

        List<Car> cars = jdbcTemplate.query(sql, 
                new BeanPropertyRowMapper(Car.class));
        return cars;
    }
}

CarService是一个服务类,其中包含一种从数据库中检索所有汽车的方法。

@Autowired
public JdbcTemplate jdbcTemplate;

JdbcTemplate注入了@Autowired注解。

List<Car> cars = jdbcTemplate.query(sql, 
        new BeanPropertyRowMapper(Car.class));

使用JdbcTemplatequery()方法,我们执行 SQL 查询。 使用BeanPropertyRowMapper将结果对象映射到Car对象。

MyController.java

package com.zetcode.web;

import com.zetcode.bean.Car;
import com.zetcode.service.CarService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class MyController {

    @Autowired
    private CarService carService;

    @RequestMapping("/index")
    public String index(Model model) {

        return "index";
    }

    @RequestMapping(value = "/all", method = RequestMethod.GET)
    public ModelAndView all() {

        List<Car> cars = carService.getAllCars();

        ModelAndView model = new ModelAndView("allCars");
        model.addObject("cars", cars);

        return model;
    }
}

MyController是控制器类。 它具有两个请求 URL 的映射:/index/all

@Autowired
private CarService carService;

注入CarService

@RequestMapping("/index")
public String index(Model model) {

    return "index";
}

通过返回index.ftl文件来解决此请求。 这些视图位于WEB-INF/views目录中。

@RequestMapping(value = "/all", method = RequestMethod.GET)
public ModelAndView all() {

    List<Car> cars = carService.getAllCars();

    ModelAndView model = new ModelAndView("allCars");
    model.addObject("cars", cars);

    return model;
}

在这里,我们调用CarServicegetAllCars()方法并创建ModelAndView对象。 所检索的数据被发送到allCars.ftl模板。

index.ftl

<!DOCTYPE html>
<html>
    <head>
        <title>Home page</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <p>Showing <a href="all.html">all cars</a></p>
    </body>
</html>

这是index.ftl文件。

allCars.ftl

<!DOCTYPE html>
<html>
    <head>
        <title>Cars</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        </head>
    <body>

        <table>
            <tr>
                <th>Id</th>  
                <th>Name</th>  
                <th>Price</th>
            </tr>        

            <#list cars as car>
                <tr>
                    <td>${car.id}</td> 
                    <td>${car.name}</td> 
                    <td>${car.price}</td>
                </tr>
            </#list>        
        </table>                
    </body>
</html>

该模板文件处理从数据库发送的数据。

<#list cars as car>

#list指令列出了数据集合。

Showing all cars

图:显示所有汽车

MySQL 数据库中的数据显示在 Opera 浏览器中。

在本教程中,我们创建了一个经典的 Spring 应用,该应用使用JdbcTemplate对 MySQL 数据库执行了 SQL 语句。 我们使用了 HikariCP 连接池。 Spring 应用使用 FreeMarker 模板引擎,并已部署在 Tomcat 服务器上。 您可能也对这些相关教程感兴趣:使用 HikariCP 连接池JdbcTemplate教程Spring 单例范围 bean 教程Spring Web 应用简介Spring Boot 第一个 Web 应用Java 教程

Spring Web 应用简介

原文: http://zetcode.com/articles/springwebfirst/

在本教程中,我们将在 Spring 中创建简单的 Web 应用。 创建了三个 Web 应用。 每个应用都以不同的方式配置。

在我们的 Spring Web 应用中,我们使用 Spring 5 和 Thymeleaf 3。

Spring 是流行的 Java 应用框架。 Spring Boot 致力于以最小的努力来创建独立的,生产级的基于 Spring 的应用。

有三种配置 Spring Web 应用的基本方法:

  • XML 格式
  • Java 配置
  • Spring Boot 自动配置

传统上,Spring 使用 XML 文件来配置应用。 后来,创建了一种新方法,其中在 Java 配置类中完成配置。 Spring Boot 自动配置魔术是配置 Spring Web 应用的最新方法。

使用 XML 的 Spring Web 应用配置

在第一个示例中,我们创建一个以 XML 文件配置的 Spring Web 应用。

pom.mxl
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           └───controller
│   │                   HomeController.java
│   ├───resources
│   └───webapp
│       │   index.html
│       └───WEB-INF
│           │   spring-servlet.xml
│           │   web.xml
│           └───templates
│                   showMessage.html
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springwebfirst</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.25</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>        

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

        </plugins>
    </build>

</project>

这是 Maven 构建文件。 我们具有以下依赖关系:slf4j-apislf4j-simple用于日志记录,javax.servlet-api用于 Java Servlet 技术,thymeleaf-spring5thymeleaf用于 Thymeleaf 模板引擎,以及spring-webmvc用于创建 Spring Web MVC 应用。

maven-war-plugin创建 Web 存档(WAR)。

WEB-INF/spring-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd 
    http://www.springframework.org/schema/mvc 
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.zetcode"/>
    <mvc:annotation-driven/>
    <mvc:default-servlet-handler/>

    <bean id="templateResolver" 
            class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
        <property name="prefix" value="/WEB-INF/templates/"/>
        <property name="suffix" value=".html"/>
        <property name="templateMode" value="HTML"/>
    </bean>

    <bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="templateEngine" ref="templateEngine"/>
    </bean>

    <bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
        <property name="templateResolver" ref="templateResolver"/>
    </bean>

</beans>

spring-servlet.xml配置 Spring Web 应用。 它启用组件扫描,Spring Web 注解(@Controller)并配置 Thymeleaf 模板。

<context:component-scan base-package="com.zetcode" />

这告诉 Spring 在哪里寻找带有@Controller@Repository@Service@Component注解的类并进行注册。 在我们的例子中,我们有一个带有@Controller注解的控制器。

<mvc:annotation-driven/>

<mvc:annotation-driven/>启用基于 Web 的 Spring 注解。

<mvc:default-servlet-handler/>

我们需要此标记来启用静态 HTML 文件。 主页上有一个静态的index.html

<bean id="templateResolver" 
        class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
    <property name="prefix" value="/WEB-INF/templates/"/>
    <property name="suffix" value=".html"/>
    <property name="templateMode" value="HTML"/>
</bean>

<bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
    <property name="templateEngine" ref="templateEngine"/>
</bean>

<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
    <property name="templateResolver" ref="templateResolver"/>
</bean>

这些行用模板引擎,模板视图解析器和模板解析器配置 Thymeleaf。 在模板解析器中,我们指定模板的位置及其扩展名。

WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
            http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
            version="4.0">

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>      

    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>    

    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

web.xml文件中,我们设置了 Spring DispatcherServlet并选择了欢迎文件。 DispatcherServlet是 Spring 的前端控制器。 该 Servlet 映射到扩展名为*.html的 URL。

com/zetcode/controller/HomeController.java

package com.zetcode.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

    @GetMapping("/message")
    public String message() {

        return "showMessage";
    }
}

HTTP 请求由控制器处理。 它准备一个模型并返回一个视图。 返回的showMessage字符串映射到位于WEB-INF/templates/目录中的showMessage.html文件。

WEB-INF/templates/showMessage.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Message</title>
</head>
<body>

<p>
    Hello there
</p>

</body>
</html>

showMessage.html文件显示一条消息。

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>
<p>
    <a href="message">Show message</a>
</p>
</body>
</html>

index.html是主页。 它包含一个链接。

使用 Java 配置进行 Spring Web 应用配置

在第二个示例中,我们创建一个在 Java 配置类中配置的 Spring Web 应用。 在该示例中,web.xmlspring-servlet.xml被替换为MyWebInitializer.javaWebConfig.java

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   ├───resources
│   └───webapp
│       └───WEB-INF
│           └───templates
│                   index.html
│                   showMessage.html
└───test
    └───java

这是项目结构。 pom.xml文件与第一个示例中的相同。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {

        var templateResolver = new SpringResourceTemplateResolver();

        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");

        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {

        var templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);

        return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver() {

        var resolver = new ThymeleafViewResolver();
        var registry = new ViewResolverRegistry(null, applicationContext);

        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);

        return resolver;
    }
}

使用WebConfig.java代替spring-servlet.xml文件。 在WebConfig中,我们使用@EnableWebMvc启用 Spring Web 注解,使用@ComponentScan启用组件扫描,并配置 Thymeleaf 模板引擎。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

使用MyWebInitializer类代替web.xml文件。 我们指定 servlet 配置类的名称。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MyController {

    @GetMapping("/")
    public String index() {
        return "index";
    }

    @GetMapping("/message")
    public String message() {
        return "showMessage";
    }
}

这是控制器。 我们有主页和showMessage页面的映射。

WEB-INF/templates/showMessage.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Message</title>
</head>
<body>
<p>Today is a sunny day!</p>
</body>
</html>

showMessage.html文件显示一条消息。

WEB-INF/templates/index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>
<p>
    <a href="message.html">Show message</a>
</p>
</body>
</html>

index.html是主页。 它包含一个链接。

Spring Boot Web 应用

在第三个示例中,我们使用 Spring Boot 创建一个 Web 应用。 Spring Boot 使用另一种默认方法。 它通过嵌入式 Web 服务器使用 JAR 存档。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
│       │   application.properties
│       ├───static
│       │       index.html
│       └───templates
│               showMessage.html
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springbootwebfirst</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
    </parent>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

这是 Maven 构建文件。 spring-boot-starter-web是使用 Spring MVC 构建 Web(包括 RESTful)应用的入门 POM。 spring-boot-starter-thymeleaf是 Thymeleaf 模板引擎的启动器 POM。

请注意,包装设置为 JAR。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MyController {

    @GetMapping("/message")
    public String message() {

        return "showMessage";
    }
}

这是 Spring Boot Web 应用的控制器类。 控制器以@Controller注解修饰。 控制器具有一个映射。 映射解析为showMessage.html模板,该模板位于WEB-INF/templates目录中。

Application.java

package com.zetcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Application设置 Spring Boot 应用。

WEB-INF/templates/showMessage.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Message</title>
</head>
<body>
<p>Today is a cold day</p>
</body>
</html>

showMessage.html显示一条简单消息。

WEB-INF/static/index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>
<p>
    <a href="message">Show message</a>
</p>
</body>
</html>

index.html是包含链接的应用的主页。 静态资源(例如,纯 HTML 文件)被放入static目录。

在本教程中,我们创建了第一个 Spring Web 应用。 您可能也对相关教程感兴趣:独立的 Spring 应用FreeMarker 教程Java 教程Spring DefaultServlet教程Spark 简介Strips 简介

Spring BeanPropertyRowMapper教程

原文: http://zetcode.com/spring/beanpropertyrowmapper/

Spring BeanPropertyRowMapper教程展示了如何使用BeanPropertyRowMapper将表行转换为指定 Bean 类的新实例。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring BeanPropertyRowMapper

BeanPropertyRowMapperRowMapper执行该表的行转换成指定的映射的目标类的一个新实例。 映射的目标类必须是顶级类,并且必须具有默认或无参数构造器。

Spring BeanPropertyRowMapper示例

以下应用使用BeanPropertyRowMappercoutries表中读取所有行。 在示例中,我们使用 MySQL 数据库。

countries.sql

CREATE TABLE countries(id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255), population INT);

INSERT INTO countries(name, population) VALUES('China', 1382050000);
INSERT INTO countries(name, population) VALUES('India', 1313210000);
INSERT INTO countries(name, population) VALUES('USA', 324666000);
INSERT INTO countries(name, population) VALUES('Indonesia', 260581000);
INSERT INTO countries(name, population) VALUES('Brazil', 207221000);
INSERT INTO countries(name, population) VALUES('Pakistan', 196626000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Bangladesh', 162099000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Russia', 146838000);
INSERT INTO countries(name, population) VALUES('Japan', 126830000);
INSERT INTO countries(name, population) VALUES('Mexico', 122273000);
INSERT INTO countries(name, population) VALUES('Philippines', 103738000);

这是我们示例的一些测试数据。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           ├───config
│   │           │       DBConfig.java
│   │           └───model
│   │                   Country.java
│   └───resources
│           db.properties
│           logback.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springbeanpropertyrowmapperex</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml文件中,我们声明了基本的 Spring 依赖关系。 BeanPropertyRowMapperspring-jdbc的一部分。

resources/db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
jdbc.username=user7
jdbc.password=s$cret

我们在外部文件中具有基本的数据库属性。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/model/Country.java

package com.zetcode.model;

import java.util.Objects;

public class Country {

    private Long id;
    private String name;
    private int population;

    public Country() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Country country = (Country) o;
        return population == country.population &&
                Objects.equals(id, country.id) &&
                Objects.equals(name, country.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, population);
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Country{");
        sb.append("id=").append(id);
        sb.append(", name='").append(name).append('\'');
        sb.append(", population=").append(population);
        sb.append('}');
        return sb.toString();
    }
}

这是Country bean。 它具有idnamepopulation属性。

com/zetcode/config/DBConfig.java

package com.zetcode.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

@Configuration
@PropertySource(value="classpath:db.properties", ignoreResourceNotFound=true)
public class DBConfig {

    @Autowired
    private Environment env;

    @Bean
    public DataSource dataSource() {

        var dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("jdbc.driver"));
        dataSource.setUrl(env.getProperty("jdbc.url"));
        dataSource.setUsername(env.getProperty("jdbc.username"));
        dataSource.setPassword(env.getProperty("jdbc.password"));

        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() {

        var template = new JdbcTemplate();
        template.setDataSource(dataSource());

        return template;
    }
}

DBConfig配置dataSourcejdbcTemplate bean。 它从db.properties文件读取配置数据。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.model.Country;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

@ComponentScan("com.zetcode")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(Application.class);
        var app = ctx.getBean(Application.class);

        app.run();

        ctx.close();
    }

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private void run() {

        var sql = "SELECT * FROM countries";

        var rowMapper = BeanPropertyRowMapper.newInstance(Country.class);
        var countries = jdbcTemplate.query(sql, rowMapper);

        countries.forEach(country -> logger.info("{}", country));
    }
}

这是主要的应用类。

var sql = "SELECT * FROM countries";

我们定义一个查询以从countries表中检索所有行。

var rowMapper = BeanPropertyRowMapper.newInstance(Country.class);

我们为Country类创建BeanPropertyRowMapper的新实例。

var countries = jdbcTemplate.query(sql, rowMapper);

JdbcTemplatequery()执行 SQL 查询。 由于BeanPropertyRowMapper,表列自动映射到 bean 属性。

$ mvn -q exec:java
12:47:37.079 INFO  com.zetcode.Application - Country{id=1, name='China', population=1382050000}
12:47:37.082 INFO  com.zetcode.Application - Country{id=2, name='India', population=1313210000}
12:47:37.083 INFO  com.zetcode.Application - Country{id=3, name='USA', population=324666000}
12:47:37.084 INFO  com.zetcode.Application - Country{id=4, name='Indonesia', population=260581000}
12:47:37.084 INFO  com.zetcode.Application - Country{id=5, name='Brazil', population=207221000}
12:47:37.085 INFO  com.zetcode.Application - Country{id=6, name='Pakistan', population=196626000}
12:47:37.086 INFO  com.zetcode.Application - Country{id=7, name='Nigeria', population=186988000}
12:47:37.087 INFO  com.zetcode.Application - Country{id=8, name='Bangladesh', population=162099000}
12:47:37.088 INFO  com.zetcode.Application - Country{id=9, name='Nigeria', population=186988000}
12:47:37.088 INFO  com.zetcode.Application - Country{id=10, name='Russia', population=146838000}
12:47:37.089 INFO  com.zetcode.Application - Country{id=11, name='Japan', population=126830000}
12:47:37.090 INFO  com.zetcode.Application - Country{id=12, name='Mexico', population=122273000}
12:47:37.090 INFO  com.zetcode.Application - Country{id=13, name='Philippines', population=103738000}

我们运行该应用。

在本教程中,我们使用BeanPropertyRowMapper将表行映射到 bean 属性。

您可能也对这些相关教程感兴趣:经典的 Spring 应用中的 JdbcTemplateSpring HikariCP 教程Java 教程,或列出了整个 Spring 教程

Spring @GetMapping教程

原文: http://zetcode.com/spring/getmapping/

Spring @GetMapping教程展示了如何使用@GetMapping注解将 HTTP GET 请求映射到特定的处理器方法。

Spring 是用于创建企业应用的流行 Java 应用框架。

@GetMapping

@GetMapping注解将 HTTP GET 请求映射到特定的处理器方法。 它是一个组合的注解,用作@RequestMapping(method = RequestMethod.GET)的快捷方式。

Spring @GetMapping示例

以下应用使用@GetMapping将两个请求路径映射到处理器方法。 在此示例中,我们使用注解来设置 Spring Web 应用。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
│           logback.xml
└───test
    └───java
        └───com
            └───zetcode
                └───controller
                        MyControllerTest.java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>getmapping</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>

</project>

pom.xml文件中,我们具有以下依存关系:logback-classicjavax.servlet-apijunitspring-webmvcspring-test

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig {

}

WebConfig通过@EnableWebMvc启用 Spring MVC 注解,并为com.zetcode包配置组件扫描。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping(value="/", produces = MediaType.TEXT_PLAIN_VALUE)
    public String index() {

        return "This is Home page";
    }

    @GetMapping(value="/hello", produces = MediaType.TEXT_PLAIN_VALUE)
    public String sayHello() {

        return "Hello there!";
    }
}

MyController提供请求路径和处理器方法之间的映射。

@RestController
public class MyController {

@RestController用于创建不使用视图技术的静态控制器。 这些方法通常返回 XML,JSON 或纯文本。

@GetMapping(value="/", produces = MediaType.TEXT_PLAIN_VALUE)
public String index() {

    return "This is Home page";
}

@GetMapping将从 GET 请求到index()方法的/根路径映射。 它返回纯文本。

com/zetcode/controller/MyControllerTest.java

package com.zetcode.controller;

import org.junit.Before;
import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

public class MyControllerTest {

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.standaloneSetup(new MyController()).build();
    }

    @Test
    public void testHomePage() throws Exception {
        this.mockMvc.perform(get("/")).andExpect(status().isOk())
                .andExpect(content().string("This is Home page"));
    }

    @Test
    public void testHelloPage() throws Exception {
        this.mockMvc.perform(get("/hello")).andExpect(status().isOk())
                .andExpect(content().string("Hello there!"));
    }
}

MyControllerTest测试两个页面。

$ curl localhost:8080
This is Home page
$ curl localhost:8080/hello
Hello there!

我们运行该应用,并使用curl工具创建两个 GET 请求。

在本教程中,我们介绍了@GetMapping注解。

您可能也对这些相关教程感兴趣: Spring @PostMapping教程Spring 单例范围 beanSpring @ComponentScan教程Spring 配置文件 XML 教程Java 教程或列出所有 Spring 教程

Spring DefaultServlet教程

原文: http://zetcode.com/spring/defaultservlet/

Spring DefaultServlet教程展示了如何在 Spring 应用中启用默认 servlet。

Spring 是流行的 Java 应用框架。 在本教程中,我们使用 Spring 5 版本。

DefaultServlet

DefaultServlet是大多数 Web 应用的默认资源服务 Servlet,用于提供 HTML 页面和图像等静态资源。

DefaultServletHttpRequestHandler尝试在启动时自动检测容器的默认 Servlet,例如 Tomcat,Jetty,Wildfly 和 Resin。 如果默认 Servlet 是使用其他名称自定义配置的,则必须明确提供默认 Servlet 的名称。

如果我们重写DefaultServlet的路由(/),则可以使用DefaultServletHandlerConfigurerenable()方法启用它,以便我们仍然可以使用容器的默认 Servlet 提供静态资源。

Spring DefaultServlet示例

在以下应用中,我们将 Spring 调度器 servlet 配置为/路径,该路径将重写默认 servlet 的路径。 我们使用DefaultServletHandlerConfigurer启用默认 servlet。

该应用提供一个简单的 HTML 主页,这是一个静态资源。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           └───config
│   │                   MyWebInitializer.java
│   │                   WebConfig.java
│   ├───resources
│   │       logback.xml
│   └───webapp
│           index.html
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>defaultservletex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

        </plugins>
    </build>

</project>

这是 Maven 构建文件。 我们具有以下依赖项:用于 Java Servlet 技术的javax.servlet-api,用于日志记录的logback-classic和用于创建 Spring Web MVC 应用的spring-webmvc

maven-war-plugin创建 Web 存档(WAR)。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

MyWebInitializer初始化 Spring Web 应用。

@Override
protected String[] getServletMappings() {
    return new String[]{"/"};
}

我们将Spring DispatcherServlet注册到/路径。 这代替了DefaultServlet; 因此,我们必须在配置文件中注册一个默认的 servlet 处理器。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

WebConfig通过@EnableWebMvc启用 Spring MVC,并通过DefaultServletHandlerConfigurerenable()方法配置DefaultServlet

@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
}

configureDefaultServletHandling()使用 URL 映射/**和相对于其他 URL 映射的最低优先级来配置DefaultServletHttpRequestHandler。 这样,静态资源请求由容器的默认 Servlet 处理。

webapp/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>

<p>
    This is home page.
</p>

</body>
</html>

这是主页。 它是静态资源,由DefaultServlet自动提供服务。

$ curl localhost:8080
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>

<p>
    This is home page.
</p>

</body>
</html>    

当我们运行应用时,将提供主页。

在本教程中,我们展示了如何在 Spring 应用中注册默认 servlet。 您可能也对相关教程感兴趣:独立的 Spring 应用Spring WebSocket 教程Spring 自定义 404 错误页面教程,Spring WebApplicationInitializer教程,Spring Web 应用简介Java 教程

Spring WebSocket 教程

原文: http://zetcode.com/spring/websocket/

Spring WebSocket 教程展示了如何在 Spring Web 应用中使用 WebSocket。

Spring 是用于创建企业应用的流行 Java 应用框架。

WebSocket

WebSocket 是一种计算机通信协议,可通过单个 TCP 连接提供全双工通信通道。 WebSocket 用于高度互动的应用,例如游戏,聊天或股票市场。

TextWebSocketHandler

Spring 使用WebSocketHandler处理 WebSocket 消息和生命周期事件。 TextWebSocketHandler是用于处理文本消息的WebSocketHandler实现。

Spring TextWebSocketHandler示例

以下应用使用TextWebSocketHandler通过 WebSocket 处理文本消息。

web.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           │       WebSocketConfig.java
│   │           └───handler
│   │                   MyWebSocketHandler.java
│   ├───resources
│   └───webapp
│       │   index.html
│       └───WEB-INF
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>textwebsocketex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>5.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

        </plugins>
    </build>

</project>

pom.xml文件中,我们具有以下依存关系:spring-webmvcjavax.servlet-apispring-websocket

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class, WebSocketConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

MyWebInitializer初始化 Spring Web 应用。 它提供了两个配置类:WebConfigWebSocket

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan("com.zetcode")
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

WebConfig配置DefaultServlet。 在我们的应用中,我们有一个静态的index.html页面,该页面由DefaultServlet处理。

com/zetcode/config/WebSocketConfig.java

package com.zetcode.config;

import com.zetcode.handler.MyWebSocketHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Autowired
    private MyWebSocketHandler myWebSocketHandler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myWebSocketHandler, "/socketHandler");
    }
}

WebSocketConfig使用@EnableWebSocket在 Spring Web 应用中配置 WebSocket。

@Autowired
private MyWebSocketHandler myWebSocketHandler;

我们注入MyWebSocketHandler。 已在registerWebSocketHandlers()中注册。

com/zetcode/config/MyWebSocketHandler.java

package com.zetcode.handler;

import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.time.LocalTime;

@Component
public class MyWebSocketHandler extends TextWebSocketHandler {

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message)
            throws Exception {

        var clientMessage = message.getPayload();

        if (clientMessage.startsWith("hello") || clientMessage.startsWith("greet")) {
            session.sendMessage(new TextMessage("Hello there!"));
        } else if (clientMessage.startsWith("time")) {
            var currentTime = LocalTime.now();
            session.sendMessage(new TextMessage(currentTime.toString()));
        } else {

            session.sendMessage(new TextMessage("Unknown command"));
        }
    }
}

MyWebSocketHandler中,我们对套接字消息做出反应。

var clientMessage = message.getPayload();

通过getPayLoad()方法,我们获得了客户端消息。

if (clientMessage.startsWith("hello") || clientMessage.startsWith("greet")) {
    session.sendMessage(new TextMessage("Hello there!"));
} else if (clientMessage.startsWith("time")) {
    var currentTime = LocalTime.now();
    session.sendMessage(new TextMessage(currentTime.toString()));
} else {

    session.sendMessage(new TextMessage("Unknown command"));
}

根据消息,我们将TextMessage发送回客户端。

webapp/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.1/semantic.min.css"
            rel="stylesheet">
</head>
<body>

<div class="ui container">

    <h1>Spring MVC 5 WebSocket</h1>

    <div class="two column grid">
        <div class="row">
            <div class="column">
                <label for="myMessage">Message</label>
            </div>

            <div class="column">
                <div class="ui input">
                    <input type="text" id="myMessage">
                </div>
            </div>
        </div>

        <div class="row">
            <div class="column">
                <label for="output">Response from Server</label>
            </div>

            <div class="column">
                <textarea rows="8" cols="50" id="output" readonly="readonly"></textarea>
            </div>
        </div>

        <div class="row">
            <button class="ui button" onclick="send()">Send</button>
        </div>

    </div>
</div>

<script>
    const socketConn = new WebSocket('ws://localhost:8080/socketHandler');

    function send() {
        const clientMsg = document.getElementById('myMessage');

        if (clientMsg.value) {
            socketConn.send(clientMsg.value);
        }
    }

    socketConn.onmessage = (e) => {

        const output = document.getElementById('output');

        output.value += `${e.data}\n`;
    }
</script>
</body>
</html>

index.html包含应用的客户端接口。

const socketConn = new WebSocket('ws://localhost:8080/socketHandler');

在 JavaScript 中,我们创建一个套接字连接。

function send() {
    const clientMsg = document.getElementById('myMessage');

    if (clientMsg.value) {
        socketConn.send(clientMsg.value);
    }
}

单击按钮后,我们将发送带有send()的短信。

socketConn.onmessage = (e) => {

    const output = document.getElementById('output');

    output.value += `${e.data}\n`;
}

收到响应后,将调用onmessage()事件处理器。 我们获得响应数据并将其添加到文本区域。

在本教程中,我们创建了一个支持 WebSocket 的简单 Spring Web 应用。

您可能也对这些相关教程感兴趣: Spring @GetMapping教程Spring DefaultServlet教程Spring Web 应用简介Java 教程

Spring WebJars 教程

原文: http://zetcode.com/spring/webjars/

Spring WebJars 教程展示了如何在 Spring Web 应用中使用 WebJars。

Spring 是用于创建企业应用的流行 Java 应用框架。

Webjars

WebJars 是打包到 JAR(Java 存档)文件中的客户端 Web 库(例如 jQuery 或 Semantic UI)。 WebJars 使前端库和资产的工作自动化。

Spring WebJar 示例

在以下示例中,我们使用 Semantic-UI WebJar。 语义 UI 是一种流行的 CSS 框架。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
│       │   logback.xml
│       └───templates
│               index.html
└───test
    └───java    

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>WebJarEx</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.4.RELEASE</spring-version>
        <thymeleaf-version>3.0.11.RELEASE</thymeleaf-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>Semantic-UI</artifactId>
            <version>2.4.1</version>
        </dependency>

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator</artifactId>
            <version>0.34</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>${thymeleaf-version}</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>${thymeleaf-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

        </plugins>
    </build>
</project>

pom.xml中,我们具有项目依赖项。

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>Semantic-UI</artifactId>
    <version>2.4.1</version>
</dependency>

我们使用语义 UI WebJar。

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>webjars-locator</artifactId>
    <version>0.34</version>
</dependency>

webjars-locator允许我们引用资产而不引用资产的版本,该版本会自动检测到。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

这是logback.xml配置

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer初始化 Spring Web 应用。 它包含一个配置类:WebConfig

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {

        var templateResolver = new SpringResourceTemplateResolver();

        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("classpath:templates/");
        templateResolver.setSuffix(".html");

        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {

        var templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);

        return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver() {

        var resolver = new ThymeleafViewResolver();
        var registry = new ViewResolverRegistry(null, applicationContext);

        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);

        return resolver;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry
                .addResourceHandler("/webjars/**")
                .addResourceLocations("/webjars/").resourceChain(false);
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

WebConfig配置 Thymeleaf 模板引擎,告诉 Spring 在哪里寻找 WebJars,并启用转发到默认 servlet 来处理静态资源的功能。

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry
            .addResourceHandler("/webjars/**")
            .addResourceLocations("/webjars/").resourceChain(false);
}

我们将通过/webjars/路径引用 WebJars。 对于版本无关的 WebJars,必须调用resourceChain()方法。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.List;

@Controller
public class MyController {

    @GetMapping(value = "/")
    public String home(Model model) {

        var words = List.of("wood", "star", "cloud", "water",
                "river", "spring");

        model.addAttribute("words", words);

        return "index";
    }
}  

MyController包含主页的一种路由。 我们向模板发送一些数据。 数据将显示在 HTML 表中,该表将使用 Semantic-UI 设置样式。

resources/templates/index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
    <link rel="stylesheet" th:href="@{/webjars/Semantic-UI/semantic.css}">
</head>
<body>

<section class="ui container">

    <h2>English words</h2>

    <table class="ui striped celled table">
        <thead>
        <tr>
            <th>Index</th>
            <th>Word</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="word : ${words}">
            <td th:text="${wordStat.index + 1}">Index</td>
            <td th:text="${word}">A word</td>
        </tr>
        </tbody>
    </table>

</section>

</body>
</html>

这是主页。

<link rel="stylesheet" th:href="@{/webjars/Semantic-UI/semantic.css}">

我们链接到semantic.css文件,该文件来自 WebJar。

<table class="ui striped celled table">

CSS 类来自 Semantic-UI 库。

在本教程中,我们创建了一个使用 Semantic-UI WebJar 样式化 HTML 表的样式。

您可能也对这些相关教程感兴趣: Spring Jetty 教程Spring @GetMapping教程Spring DefaultServlet教程Spring Web 应用简介Java 教程

Spring @MatrixVariable教程

原文: http://zetcode.com/spring/matrixvariable/

Spring @MatrixVariable教程展示了如何使用@MatrixVariable解析 URL 参数。

Spring 是用于创建企业应用的流行 Java 应用框架。

@MatrixVariable

@MatrixVariable用于解析路径段中的名称-值对,并将它们绑定到方法参数。 多对用分号分隔。 必须首先启用矩阵变量。

Spring @MatrixVariable示例

以下应用解析 URL 路径段中的名称/值对。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   ├───resources
│   └───webapp
│           index.html
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>matrixvariableex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring-version}</version>
        </dependency>

        </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

pom.xml文件中,我们具有项目依赖项。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer初始化 Spring Web 应用。 它包含一个配置类:WebConfig

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.util.UrlPathHelper;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        var urlPathHelper = new UrlPathHelper();
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

WebConfig配置 Spring Web 应用。

@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
    var urlPathHelper = new UrlPathHelper();
    urlPathHelper.setRemoveSemicolonContent(false);
    configurer.setUrlPathHelper(urlPathHelper);
}

在这里,我们启用矩阵变量。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.MatrixVariable;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class MyController {

    @GetMapping(value = "/user/{first}/{last}",
            produces = MediaType.TEXT_PLAIN_VALUE)
    public String handler1(@MatrixVariable("first") String first,
                       @MatrixVariable("last") String last) {

        return String.format("Hello %s %s", first, last);
    }

    @GetMapping(value = "/data/{user:.*}",
            produces = MediaType.TEXT_PLAIN_VALUE)
    public String handler2(@MatrixVariable Map<String, String> data) {

        return String.format("Id: %s\nFirst name: %s\nLast Name: %s\nEmail: %s\n",
                data.get("id"), data.get("first"), data.get("last"), data.get("email"));
    }

    @GetMapping(value = "/geo/{continent}",
            produces = MediaType.TEXT_PLAIN_VALUE)
    public String handler3(@PathVariable("continent") String continent,
                         @MatrixVariable("country") String country,
                         @MatrixVariable("capital") String capital) {

        return String.format("Continent: %s\nCountry: %s\nCapital: %s\n",
                continent, country, capital);
    }
}

MyController包含请求路径到处理器方法的映射。

@GetMapping(value = "/user/{first}/{last}",
        produces = MediaType.TEXT_PLAIN_VALUE)
public String handler1(@MatrixVariable("first") String first,
                    @MatrixVariable("last") String last) {

    return String.format("Hello %s %s", first, last);
}

在这里,我们使用@MatrixVariable将多个矩阵变量绑定到方法参数。

@GetMapping(value = "/data/{user:.*}",
        produces = MediaType.TEXT_PLAIN_VALUE)
public String handler2(@MatrixVariable Map<String, String> data) {

    return String.format("Id: %s\nFirst name: %s\nLast Name: %s\nEmail: %s\n",
            data.get("id"), data.get("first"), data.get("last"), data.get("email"));
}

在这里,我们将多个名称/值对映射到一个映射中。

@GetMapping(value = "/geo/{continent}",
        produces = MediaType.TEXT_PLAIN_VALUE)
public String handler3(@PathVariable("continent") String continent,
                        @MatrixVariable("country") String country,
                        @MatrixVariable("capital") String capital) {

    return String.format("Continent: %s\nCountry: %s\nCapital: %s\n",
            continent, country, capital);
}

在第三种情况下,我们将@MatrixVariable@PathVariable结合在一起。

webapp/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>

<p>
    <a href="http://localhost:8080/user/first=John/last=Doe">Greet user</a>
</p>

<p>
    <a href="http://localhost:8080/data/id=1;first=John;last=Doe;email=johndoe@gmail.com">Show user data</a>
</p>

<p>
    <a href="http://localhost:8080/geo/Europe;country=Slovakia;capital=Bratislava">Show country info</a>
</p>

</body>
</html>

这是主页。 我们有三个链接,这些链接包含使用@MatrixVariable注解解析的名称/值对。

在本教程中,我们使用@MatrixVariable解析路径段上的名称/值对并将其绑定到方法参数。

您可能也对这些相关教程感兴趣: Spring @GetMapping教程Spring DefaultServlet教程Spring Web 应用简介Java 教程

Spring Jetty 教程

原文: http://zetcode.com/spring/jetty/

Spring Jetty 教程显示了如何在 Jetty Web 服务器上运行 Spring Web 应用。

Spring 是用于创建企业应用的流行 Java 应用框架。

Jetty

Jetty Web 服务器是一个 HTTP 服务器和 Servlet 容器,能够通过独立或嵌入式实例提供静态和动态内容。

Spring Jetty 的例子

在以下示例中,我们创建一个简单的 Spring Web 应用并将其部署在 Jetty Web 服务器上。 为此,我们使用jetty-maven-plugin

该应用显示几个英语单词。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
│       │   logback.xml
│       └───templates
│               index.html
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>SpringJettyEx</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
        <thymeleaf-version>3.0.11.RELEASE</thymeleaf-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>${thymeleaf-version}</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>${thymeleaf-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>
        </plugins>
    </build>
</project>

pom.xml中,我们具有项目依赖项。

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.4.14.v20181114</version>
</plugin>

jetty-maven-plugin允许我们使用mvn jetty:run运行嵌入式 Jetty 服务器。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

这是logback.xml配置

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer初始化 Spring Web 应用。 它包含一个配置类:WebConfig

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {

        var templateResolver = new SpringResourceTemplateResolver();

        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("classpath:/templates/");
        templateResolver.setSuffix(".html");

        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {

        var templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);

        return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver() {

        var resolver = new ThymeleafViewResolver();
        var registry = new ViewResolverRegistry(null, applicationContext);

        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);

        return resolver;
    }
}

WebConfig配置 Thymeleaf 模板引擎。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;

@Controller
public class MyController {

    @GetMapping(value = "/", produces = MediaType.TEXT_HTML_VALUE)
    public String home(Model model) {

        var words = List.of("mountain", "noon", "rock", "river", "spring");

        model.addAttribute("words", words);

        return "index";
    }
}

MyController包含主页的一种路由。 我们向模板发送一些数据。 数据将显示在 HTML 表中。

resources/templates/index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>

<h2>English words</h2>

<table">
    <thead>
    <tr>
        <th>Index</th>
        <th>Word</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="word : ${words}">
        <td th:text="${wordStat.index + 1}">Index</td>
        <td th:text="${word}">A word</td>
    </tr>
    </tbody>
</table>

</body>
</html>

这是主页。

$ mvn jetty:run    

我们运行 Jetty 服务器。 我们导航到localhost:8080以获取主页。

在本教程中,我们创建了一个 Spring Web 应用并将其部署在嵌入式 Jetty 服务器上。

您可能也对这些相关教程感兴趣: Spring WebJars 教程Spring DefaultServlet教程Spring Web 应用简介Java 教程

Spring 自定义 404 错误页面教程

原文: http://zetcode.com/spring/custom404page/

Spring 自定义 404 错误页面教程展示了如何在 Spring Web 应用中创建自定义 404 错误页面。

Spring 是用于创建企业应用的流行 Java 应用框架。

404 代码

HTTP 404 或 404 未找到是计算机网络通信中的超文本传输​​协议(HTTP)标准响应代码,用于指示客户端能够与给定服务器进行通信,但是服务器找不到所请求的资源。

Spring 自定义 404 错误页面示例

以下应用使用创建自定义 404 错误页面。 默认情况下,当找不到资源时,将显示 Tomcat 的 404 错误页面。

src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   ControllerAdvisor.java
│   │                   MyController.java
│   └───resources
│       │   logback.xml
│       └───templates
│           │   index.html
│           └───error
│                   404.html
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>custom404page</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

        </plugins>
    </build>

</project>

pom.xml文件中,我们具有以下依存关系:logback-classicjavax.servlet-apispring-webmvcthymeleaf-spring5以及thymeleaf

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

这是logback.xml配置文件。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }

    @Override
    protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
        var dispatcher = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
        dispatcher.setThrowExceptionIfNoHandlerFound(true);
        return dispatcher;
    }
}

MyWebInitializer初始化 Spring Web 应用。 它包含一个配置类:WebConfig

@Override
protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
    var dispatcher = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
    dispatcher.setThrowExceptionIfNoHandlerFound(true);
    return dispatcher;
}

使用setThrowExceptionIfNoHandlerFound(),我们将 Spring 配置为在找不到资源时抛出NoHandlerFoundException。 如果我们在此行中添加注释,则会显示 Web 服务器的 404 错误页面。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {

        var templateResolver = new SpringResourceTemplateResolver();

        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("classpath:/templates/");
        templateResolver.setSuffix(".html");

        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {

        var templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);

        return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver() {

        var resolver = new ThymeleafViewResolver();
        var registry = new ViewResolverRegistry(null, applicationContext);

        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);

        return resolver;
    }
}

WebConfig配置 Thymeleaf 模板引擎。 Thymeleaf 模板文件位于类路径的templates子目录中。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.time.LocalDateTime;

@Controller
public class MyController {

    @GetMapping(value = "/", produces = MediaType.TEXT_HTML_VALUE)
    public String home(Model model) {

        model.addAttribute("now", LocalDateTime.now());

        return "index";
    }
}    

MyController包含主页的一种路由。

com/zetcode/controller/ControllerAdvisor.java

package com.zetcode.controller;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;

@ControllerAdvice
public class ControllerAdvisor {

    @ExceptionHandler(NoHandlerFoundException.class)
    public ModelAndView handle(Exception ex) {

        var mv = new ModelAndView();
        mv.addObject("message", ex.getMessage());
        mv.setViewName("error/404");

        return mv;
    }
}

ControllerAdvisor包含NoHandlerFoundException的处理器。 它显示404.html错误页面,位于resources/templates/error/404.html中。

resources/templates/error/404.html

<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Resource not found</title>
</head>
<body>

<h2>404 - resource not found</h2>

<p>
    <span th:text="${message}" th:remove="tag"></span>
</p>

</body>
</html>

404.html是我们的自定义 404 错误页面。

resources/templates/index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>

<p>
    This is home page.
</p>

<p>
    Today is <span th:text="${now}"></span>
</p>
</body>
</html>

这是主页。

在本教程中,我们在 Spring 应用中创建了一个自定义 404 错误页面。

您可能也对这些相关教程感兴趣: Spring WebJars 教程Spring @GetMapping教程Spring DefaultServlet教程Spring Web 应用简介Java 教程

Spring WebApplicationInitializer教程

http://zetcode.com/spring/webapplicationinitializer/

Spring WebApplicationInitializer教程展示了如何使用WebApplicationInitializer以编程方式引导 Spring Web 应用。

Spring 是用于创建企业应用的流行 Java 应用框架。

WebApplicationInitializer

WebApplicationInitializer用于引导 Spring Web 应用。 WebApplicationInitializer注册一个 Spring DispatcherServlet并创建一个 Spring Web 应用上下文。 通常,开发者使用AbstractAnnotationConfigDispatcherServletInitializer(它是WebApplicationInitializer的实现)来创建 Spring Web 应用。

传统上,基于 Servlet 的 Java Web 应用使用web.xml文件来配置 Java Web 应用。 从 Servlet 3.0 开始,可以通过 Servlet 上下文监听器以编程方式创建 Web 应用。

Spring WebApplicationInitializer示例

以下应用使用WebApplicationInitializer创建 Spring Web 应用。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>mockmvcex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

        </plugins>
    </build>
</project>

pom.xml文件中,我们具有以下依存关系:logback-classic javax.servlet-apispring-webmvc

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

public class MyWebInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        var ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(WebConfig.class);
        ctx.setServletContext(servletContext);

        var servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.setLoadOnStartup(1);
        servlet.addMapping("/");
    }
}

MyWebInitializer实现WebApplicationInitializer接口。 引导代码在onStartup()方法中。

var ctx = new AnnotationConfigWebApplicationContext();
ctx.register(WebConfig.class);
ctx.setServletContext(servletContext);

我们创建一个AnnotationConfigWebApplicationContext并向register()注册一个 Web 配置文件。 我们将应用上下文与 Servlet 上下文绑定。

var servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");

在这里,我们注册一个 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.zetcode")
public class WebConfig {
}

WebConfig通过@EnableWebMvc启用 Spring MVC 注解,并为com.zetcode包配置组件扫描。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping(value = "/", produces = MediaType.TEXT_PLAIN_VALUE)
    public String home() {

        return "This is home page";
    }
}

MyController是一种 RESTful 控制器,具有一个映射。

$ curl localhost:8080
This is home page

我们使用curl工具连接到主页。

在本教程中,我们使用WebApplicationInitializer创建了一个简单的 Spring Web 应用。

您可能也对这些相关教程感兴趣: Spring @GetMapping教程Spring DefaultServlet教程Spring Web 应用简介Java 教程

Spring BindingResult教程

原文: http://zetcode.com/spring/bindingresult/

Spring BindingResult教程展示了如何使用BindingResult来获取验证结果。

Spring 是用于创建企业应用的流行 Java 应用框架。

BindingResult

BindingResult保存验证和绑定的结果,并包含可能发生的错误。 BindingResult必须紧随经过验证的模型对象之后,否则 Spring 无法验证该对象并引发异常。

Spring BindingResult示例

以下应用验证用户表单,并使用BindingResult存储验证结果。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           ├───controller
│   │           │       MyController.java
│   │           └───form
│   │                   UserForm.java
│   └───resources
│       └───templates
│               form.html
│               showInfo.html
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>bindingresultex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
        <thymeleaf-version>3.0.11.RELEASE</thymeleaf-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.10.Final</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>${thymeleaf-version}</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>${thymeleaf-version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

pom.xml文件中,我们具有项目依赖项。

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.10.Final</version>
</dependency>

我们使用hibernate-validator进行验证。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer初始化 Spring Web 应用。 它包含一个配置类:WebConfig

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {

        var templateResolver = new SpringResourceTemplateResolver();

        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("classpath:/templates/");
        templateResolver.setSuffix(".html");

        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {

        var templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);

        return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver() {

        var resolver = new ThymeleafViewResolver();
        var registry = new ViewResolverRegistry(null, applicationContext);

        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);

        return resolver;
    }
}

WebConfig配置 Thymeleaf 模板引擎。 Thymeleaf 模板文件位于类路径的templates子目录中。

com/zetcode/form/UserForm.java

package com.zetcode.form;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

public class UserForm {

    @NotBlank
    @Size(min=2)
    private String name;

    @NotBlank
    @Email
    private String email;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

这是一个表单 bean。 它包含一些验证注解。

@NotBlank
@Size(min=2)
private String name;

name 属性不能为空,并且必须至少包含 2 个字符。

@NotBlank
@Email
private String email;

email 属性不能为空,并且必须是格式正确的电子邮件。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import com.zetcode.form.UserForm;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.validation.Valid;

@Controller
public class MyController {

    @GetMapping(value = "/")
    public String form(UserForm userForm) {

        return "form";
    }

    @PostMapping("/")
    public String checkForm(@Valid UserForm userForm, BindingResult bindingResult,
                            RedirectAttributes atts) {

        if (bindingResult.hasErrors()) {
            return "form";
        }

        atts.addAttribute("name", userForm.getName());
        atts.addAttribute("email", userForm.getEmail());

        return "redirect:/showInfo";
    }

    @GetMapping("/showInfo")
    public String showInfo(@ModelAttribute("name") String name,
                           @ModelAttribute("email") String email) {

        return "showInfo";
    }
}

MyController包含请求路径到处理器方法的映射。

@GetMapping(value = "/")
public String form(UserForm userForm) {

    return "form";
}

主页返回一个包含表单的视图。 UserForm bean 正在支持表单。 它将使用来自表单的数据进行填充。

@PostMapping("/")
public String checkForm(@Valid UserForm userForm, BindingResult bindingResult,
                        RedirectAttributes atts) {
...

我们用@Valid验证UserForm bean。 验证结果存储在BindingResult中。

if (bindingResult.hasErrors()) {
    return "form";
}

如果绑定结果包含错误,我们将返回表格。

atts.addAttribute("name", userForm.getName());
atts.addAttribute("email", userForm.getEmail());

return "redirect:/showInfo";

遵循发布后重定向模式,成功验证后,我们将重定向到showInfo视图。 为了不丢失输入,我们将它们存储在RedirectAttributes中。

@GetMapping("/showInfo")
public String showInfo(@ModelAttribute("name") String name,
                        @ModelAttribute("email") String email) {

    return "showInfo";
}

@ModelAttribute将请求属性nad放入模型对象,然后将其发送到showInfo视图。

resources/templates/form.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>User form</title>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.1/semantic.min.css"
          rel="stylesheet">
</head>
<body>

<section class="ui container">

    <form action="#" class="ui form" th:action="@{/}" th:object="${userForm}" method="post">
        <div class="field">
            <label>Name:</label>
            <input type="text" th:field="*{name}">
            <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</span>
        </div>

        <div class="field">

            <label>Email:</label>

            <input type="text" th:field="*{email}">
            <span th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Email Error</span>
        </div>

        <button class="ui button" type="submit">Submit</button>

    </form>

</section>

</body>
</html>

根页面包含表单。

<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.1/semantic.min.css"
    rel="stylesheet">

表单使用语义 UI 设置样式。

<form action="#" class="ui form" th:action="@{/}" th:object="${userForm}" method="post">

th:object引用用户表单 bean。 这不是一个类名,而是一个 Spring bean 名称。 因此它是小写的。

<input type="text" th:field="*{name}">

输入被映射到userFormname属性。

<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</span>

此行显示可能的验证错误。

resources/templates/showInfo.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Show info</title>
</head>
<body>

<p>
    Successfully added user <span th:text="${name}" th:remove="tag"></span> with email
    <span th:text="${email}" th:remove="tag"></span>
</p>

</body>
</html>

此视图显示输入的信息。

在本教程中,我们在验证表单时使用了BindingResult

您可能也对这些相关教程感兴趣: Spring @GetMapping教程Spring DefaultServlet教程Spring Web 应用简介Java 教程

Spring FreeMarker 教程

原文: http://zetcode.com/spring/freemarker/

Spring FreeMarker 教程展示了如何在 Spring 应用中使用 FreeMarker 模板引擎。

Spring 是用于创建企业应用的流行 Java 应用框架。

FreeMarker

FreeMarker 是适用于 Web 和独立环境的服务器端 Java 模板引擎。 模板使用 FreeMarker 模板语言(FTL)编写,这是一种简单的专用语言。 FreeMarker 的模板有.ftl扩展。

Spring FreeMarker 示例

以下应用使用 FreeMarker 生成视图。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           ├───controller
│   │           │       MyController.java
│   │           └───service
│   │                   WordService.java
│   └───resources
│       │   logback.xml
│       └───templates
│               index.ftl
│               showWords.ftl
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springfreemarkerex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>
        </plugins>
    </build>
</project>

pom.xml中,我们具有必要的依赖项。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public FreeMarkerViewResolver freemarkerViewResolver() {

        var resolver = new FreeMarkerViewResolver();
        resolver.setCache(true);
        resolver.setSuffix(".ftl");
        return resolver;
    }

    @Bean
    public FreeMarkerConfigurer freemarkerConfig() {

        var freeMarkerConfigurer = new FreeMarkerConfigurer();
        freeMarkerConfigurer.setTemplateLoaderPath("classpath:/templates/");
        return freeMarkerConfigurer;
    }
}

WebConfig配置 FreeMarker 模板引擎。 我们将模板文件的位置设置为classpath上的templates目录。 (resources在类路径上。)

com/zetcode/service/WordService.java

package com.zetcode.service;

import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class WordService {

    private final List<String> words = List.of("pen", "sky",
            "rock", "forest", "falcon", "eagle");

    public List<String> all() {

        return words;
    }
}

WordService返回几个字。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import com.zetcode.service.WordService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MyController {

    @GetMapping(value = "/")
    public String home() {

        return "index";
    }

    @GetMapping(value = "/words")
    public String showWords(Model model, WordService wordService) {

        var words = wordService.all();
        model.addAttribute("words", words);

        return "showWords";
    }
}

MyController提供请求路径和处理器方法之间的映射。 我们有两个映射:home页面和showWords页面。

var words = wordService.all();
model.addAttribute("words", words);

我们使用wordService检索所有单词并将其放入模型中。 该模型将传递到 FreeMarker,后者将处理模板中的数据。

resources/templates/index.ftl

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>

<p>
    <a href="words">Show words</a>
</p>

</body>
</html>

主页包含显示所有单词的锚点。

resources/templates/showWords.ftl

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Show words</title>
</head>
<body>

<h2>List of words</h2>

<ul>
<#list words as word>
    <li>${word}</li>
</#list>
</ul>

</body>
</html>

使用 FreeMarker 的list指令,我们可以显示 HTML 列表中的所有单词。

$ mvn jetty:run

我们运行服务器并定位到localhost:8080以获取具有锚点的主页。

在本教程中,我们使用了FreeMarker模板引擎。

您可能也对这些相关教程感兴趣: Spring @Configuration教程Java 教程或列出所有 Spring 教程

Spring Thymeleaf 教程

原文: http://zetcode.com/spring/thymeleaf/

Spring Thymeleaf 教程展示了如何在 Spring 应用中使用 Thymeleaf 模板引擎。

Spring 是用于创建企业应用的流行 Java 应用框架。

Thymeleaf

Thymeleaf 是适用于 Web 和独立环境的服务器端 Java 模板引擎。 它提供了完整的 Spring Framework 集成。

Spring Thymeleaf 示例

以下应用使用 Thymeleaf 生成视图。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           ├───controller
│   │           │       MyController.java
│   │           └───service
│   │                   WordService.java
│   └───resources
│       │   logback.xml
│       └───templates
│               index.html
│               showWords.html
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springthymeleafex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

pom.xml中,我们具有必要的依赖项。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {

        var templateResolver = new SpringResourceTemplateResolver();

        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("classpath:/templates/");
        templateResolver.setSuffix(".html");

        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {

        var templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);

        return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver() {

        var resolver = new ThymeleafViewResolver();
        var registry = new ViewResolverRegistry(null, applicationContext);

        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);

        return resolver;
    }
}

WebConfig配置 Thymeleaf 模板引擎。 我们将模板文件的位置设置为classpath上的templates目录。 (resources在类路径上。)

com/zetcode/service/WordService.java

package com.zetcode.service;

import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class WordService {

    private final List<String> words = List.of("pen", "sky",
            "rock", "forest", "falcon", "eagle");

    public List<String> all() {

        return words;
    }
}

WordService返回几个字。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import com.zetcode.service.WordService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MyController {

    @GetMapping(value = "/")
    public String home() {

        return "index";
    }

    @GetMapping(value = "/words")
    public String showWords(Model model, WordService wordService) {

        var words = wordService.all();
        model.addAttribute("words", words);

        return "showWords";
    }
}

MyController提供请求路径和处理器方法之间的映射。 我们有两个映射:home页面和showWords页面。

var words = wordService.all();
model.addAttribute("words", words);

我们使用wordService检索所有单词并将其放入模型中。 该模型将传递给 Thymeleaf,后者将处理模板中的数据。

resources/templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>

<p>
    <a href="words">Show words</a>
</p>

</body>
</html>

主页包含显示所有单词的锚点。

resources/templates/showWords.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Words</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body>

<h2>List of words</h2>

<ul th:each="word : ${words}">
    <li th:text="${word}">word</li>
</ul>

</body>
</html>

使用 Thymeleaf 的th:each指令,我们可以显示 HTML 列表中的所有单词。

$ mvn jetty:run

我们运行服务器并定位到localhost:8080以获取具有锚点的主页。

在本教程中,我们使用了Thymeleaf模板引擎。

您可能对这些相关教程也感兴趣: Spring Freemarker 教程Spring @Configuration教程Java 教程或列出所有 Spring 教程

Spring @PostMapping教程

原文: http://zetcode.com/spring/postmapping/

Spring @PostMapping教程显示了如何使用@PostMapping注解将 HTTP POST 请求映射到特定的处理器方法。

Spring 是用于创建企业应用的流行 Java 应用框架。

@PostMapping

@PostMapping注解将 HTTP POST 请求映射到特定的处理器方法。 它是一个组合的注解,用作@RequestMapping(method = RequestMethod.POST)的快捷方式。

Spring @PostMapping示例

以下应用使用@PostMapping创建新资源。 在此示例中,我们使用注解来设置 Spring Web 应用。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           ├───controller
│   │           │       MyController.java
│   │           ├───model
│   │           │       Post.java
│   │           └───service
│   │                   PostService.java
│   └───resources
│           logback.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>postmappingex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

pom.xml文件中,我们具有项目依赖项。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig {

}

WebConfig通过@EnableWebMvc启用 Spring MVC 注解,并为com.zetcode包配置组件扫描。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import com.zetcode.model.Post;
import com.zetcode.service.PostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.http.HttpServletRequest;
import java.util.Set;

import static org.springframework.http.ResponseEntity.ok;

@Controller
public class MyController {

    @Autowired
    private PostService postService;

    @GetMapping(value="/posts")
    public ResponseEntity<Set<Post>> all() {
        return ok().body(postService.all());
    }

    @PostMapping(value = "/posts")
    public ResponseEntity<Post> createPost(HttpServletRequest request,
                                        UriComponentsBuilder uriComponentsBuilder) {

        var content = request.getParameter("content");

        var post = new Post();
        post.setContent(content);

        post = postService.save(post);

        UriComponents uriComponents =
                uriComponentsBuilder.path("/posts/{id}").buildAndExpand(post.getId());
        var location = uriComponents.toUri();

        return ResponseEntity.created(location).build();
    }
}

MyController提供请求路径和处理器方法之间的映射。

注意:这是一个很好的做法,在响应头返回新创建资源的位置。

@PostMapping(value = "/posts")
public ResponseEntity<Post> createPost(HttpServletRequest request,
                                    UriComponentsBuilder uriComponentsBuilder) {

@PostMappingcreatePost()方法映射到/posts URL。

var content = request.getParameter("content");

我们获得 POST 请求的content参数。

var post = new Post();
post.setContent(content);

post = postService.save(post);

创建一个新帖子,并将其保存在一个帖子服务中。

UriComponents uriComponents =
    uriComponentsBuilder.path("/posts/{id}").buildAndExpand(post.getId());
var location = uriComponents.toUri();

使用UriComponentsBuilder构建位置 URI。

return ResponseEntity.created(location).build();

返回带有位置 URI 的响应实体。

com/zetcode/model/Post.java

package com.zetcode.model;

import java.util.Objects;

public class Post {

    private Long id;
    private String content;

    public Post() {

    }

    public Post(Long id, String content) {
        this.id = id;
        this.content = content;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Post post = (Post) o;
        return Objects.equals(id, post.id) &&
                Objects.equals(content, post.content);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, content);
    }
}

这是一个简单的Post bean。 它具有两个属性:idcontent

com/zetcode/service/PostService.java

package com.zetcode.service;

import com.zetcode.model.Post;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

@Service
public class PostService {

    private final AtomicLong counter = new AtomicLong();

    private final Set<Post> posts = new HashSet<>(Set.of(new Post(counter.incrementAndGet(), "Post one"),
            new Post(counter.incrementAndGet(), "Post two"), new Post(counter.incrementAndGet(), "Post three"),
            new Post(counter.incrementAndGet(), "Post four")));

    public Post save(Post p) {

        var post = new Post(counter.incrementAndGet(), p.getContent());
        this.posts.add(post);

        return post;
    }

    public Set<Post> all() {

        return this.posts;
    }
}

PostService具有保存帖子并返回所有帖子的方法。 我们没有实现数据库层。 相反,我们使用一个简单的内存集合。

$ mvn jetty:run

我们运行 Jetty 服务器。

$ curl -i -d "content=Post five" -X POST http://localhost:8080/posts
HTTP/1.1 201 Created
Date: Tue, 30 Apr 2019 09:49:10 GMT
Location: http://localhost:8080/posts/5
Content-Length: 0
Server: Jetty(9.4.14.v20181114)

创建一个新帖子。 注意位置标头。

$ curl localhost:8080/posts
[{"id":3,"content":"Post three"},{"id":4,"content":"Post four"},
{"id":1,"content":"Post one"},{"id":5,"content":"Post five"},{"id":2,"content":"Post two"}]

我们得到所有帖子。

在本教程中,我们介绍了@PostMapping注解。

您可能也对这些相关教程感兴趣: Spring @GetMapping教程Spring @RequestMapping教程Spring @MatrixVariable教程Java 教程,或列出所有 Spring 教程

Spring ResourceHandlerRegistry教程

原文: http://zetcode.com/spring/resourcehandlerregistry/

Spring ResourceHandlerRegistry教程展示了如何在 Spring Web 应用中提供静态资产,例如图像,CSS 或 JavaScript 文件。

Spring 是用于创建企业应用的流行 Java 应用框架。

ResourceHandlerRegistry

ResourceHandlerRegistry存储用于通过 Spring MVC 服务静态资源(例如图像,css 文件等)的资源处理器的注册。 它允许设置为在 Web 浏览器中高效加载而优化的缓存头。 可以在 Web 应用根目录下,类路径等位置之外的位置提供资源。

Spring ResourceHandlerRegistry示例

以下应用使用ResourceHandlerRegistry在 Spring Web 应用中注册静态资产。 我们使用addResourceHandlers()为 CSS 和 JavaScript 文件注册处理器和位置。

我们将 Thymeleaf 用作视图引擎。 我们使用 Thymeleaf 的@{}语法指向静态资源。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   ├───resources
│   │   │   logback.xml
│   │   └───static
│   │       ├───css
│   │       │       format.css
│   │       └───js
│   │               main.js
│   └───webapp
│       └───WEB-INF
│           └───templates
│                   homePage.html
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>staticresources</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

        </plugins>
    </build>

</project>

pom.xml文件中,我们具有以下依存关系:logback-classicjavax.servlet-apispring-webmvcthymeleaf-spring5thymeleaf

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/css/format.css

p {
    background-color: aquamarine;
}

这是format.css文件。 它格式化p元素。

resources/js/main.js

const el = document.getElementById("block");
el.style.border = '1px dashed gray';

这是main.js文件。 它将边框添加到div元素。 请注意,即使 JavaScript 在科学方面提供了动态功能,但从 Spring 的角度来看,它仍被视为静态资源。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/*"};
    }
}

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {

        var templateResolver = new SpringResourceTemplateResolver();

        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");

        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {

        var templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);

        return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver() {

        var resolver = new ThymeleafViewResolver();
        var registry = new ViewResolverRegistry(null, applicationContext);

        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);

        return resolver;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/");
    }
}

WebConfig通过@EnableWebMvc启用 Spring MVC 注解,并为com.zetcode包配置组件扫描。 它设置 Thymeleaf 引擎并注册静态资源处理器。

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/");
    registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/");
}

我们重写addResourceHandlers()来注册 JavaScript 和 CSS 文件的处理器和位置。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MyController {

    @GetMapping(value="/")
    public String homePage() {

        return "homePage";
    }
}

MyController提供主页的映射。 在应用中,我们仅使用一个视图。

WEB-INF/templates/homePage.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
    <link rel="stylesheet" th:href="@{/css/format.css}">
</head>
<body>

<div id="block">

<p>
    This is home page.
</p>

</div>

<script th:src="@{/js/main.js}"></script>
</body>
</html>

homePage.html是主页的视图。 它使用静态资源; 一个 CSS 和一个 JavaScript 文件。

<link rel="stylesheet" th:href="@{/css/format.css}">

我们使用特定的 Thymeleaf 语法引用静态文件。

在本教程中,我们展示了如何向 Spring 的ResourceHandlerRegistry注册静态资源。

您可能也对这些相关教程感兴趣: Spring BeanDefinitionBuilder教程Spring 资源教程Spring @GetMapping教程Java 教程

SpringRunner教程

原文: http://zetcode.com/spring/springrunner/

SpringRunner教程展示了如何使用SpringRunner测试 Spring 应用。

Spring 是流行的 Java 应用框架。 在本教程中,我们使用 Spring 5 版本。

SpringRunner

SpringRunnerSpringJUnit4ClassRunner的别名,该别名将JUnit测试库与 Spring TestContext Framework 结合在一起。 我们将其与@RunWith(SpringRunner.class)一起使用。

使用SpringRunner,我们可以实现基于 JUnit 4 的标准单元测试和集成测试。

Spring TestContext Framework 提供了通用的,注解驱动的单元和集成测试支持,这些支持与使用中的测试框架(JUnit,TestNG)无关。

SpringRunner示例

在以下应用中,我们使用SprigRunner测试一个简单的服务。 该应用是一个 Spring 独立控制台应用。

该应用包含两个属性文件:一个文件用于生产应用,另一个文件用于测试。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           ├───config
│   │           │       AppConfig.java
│   │           └───service
│   │                   HelloService.java
│   └───resources
│           application.properties
│           logback.xml
└───test
    ├───java
    │   └───com
    │       └───zetcode
    │           └───service
    │                   HelloServiceTest.java
    └───resources
            appTest.properties

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springrunnerex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>com.zetcode.Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

这是 Maven 构建文件。 我们具有以下依赖项:logback-classic用于记录日志,spring-contextspring-core是基本的 Spring 依赖项,spring-test用于测试,hamcrest-all包含 Hamcrest 匹配库的所有模块,而JUnit是用于单元测试的库。

exec-maven-plugin帮助执行系统和 Java 程序。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

resources/application.properties

app.message=Hello there!

application.properties包含一个消息属性,由HelloMessage服务显示。

com/zetcode/AppConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@ComponentScan(basePackages = "com.zetcode")
@PropertySource("application.properties")
public class AppConfig {
}

AppConfig配置组件扫描并从提供的文件中加载属性。

com/zetcode/servide/HelloService.java

package com.zetcode.service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class HelloService {

    @Value("${app.message}")
    private String message;

    public String sayHello() {

        return message;
    }
}

HelloService返回从application.properties文件检索到的消息。

com/zetcode/Application.java

package com.zetcode;

import com.zetcode.config.AppConfig;
import com.zetcode.service.HelloService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(AppConfig.class);

        var app = ctx.getBean(Application.class);
        app.run();

        ctx.close();
    }

    @Autowired
    private HelloService helloService;

    private void run() {

        logger.info("Calling hello service");
        logger.info(helloService.sayHello());

    }
}

应用使用HelloService将消息打印到控制台。

$ mvn -q exec:java
17:50:54.118 INFO  com.zetcode.Application - Calling hello service
17:50:54.118 INFO  com.zetcode.Application - Hello there!

我们运行该应用。

resources/appTest.properties

app.message=Testing hello message

appTest.properties专用于测试。

com/zetcode/service/HelloServiceTest.java

package com.zetcode.service;

import com.zetcode.config.AppConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes={HelloService.class})
@TestPropertySource("/appTest.properties")
public class HelloServiceTest {

    @Value("${app.message}")
    private String message;

    @Autowired
    private HelloService helloService;

    @Test
    public void testHelloMessage() {

        var message = helloService.sayHello();
        assertThat(message, equalTo(message));
    }
}

HelloServiceTest用于测试HelloService类。

@RunWith(SpringRunner.class)
@ContextConfiguration(classes={HelloService.class})
@TestPropertySource("/appTest.properties")
public class HelloServiceTest {

测试类用@RunWith(SpringRunner.class)注解。 @ContextConfiguration定义了类级别的元数据,用于确定如何加载和配置用于集成测试的应用上下文。 此外,我们还提供了@TestPropertySource自定义测试属性文件。

@Value("${app.message}")
private String message;

我们从appTest.properties文件注入消息。

@Autowired
private HelloService helloService;

我们注入HelloMessage服务类。 这是要测试的类。

@Test
public void testHelloMessage() {

    var message = helloService.sayHello();
    assertThat(message, equalTo(message));
}

我们测试来自service方法的消息是否等于注入的字符串值。

$ mvn -q test

-------------------------------------------------------
    T E S T S
-------------------------------------------------------
Running com.zetcode.service.HelloServiceTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.489 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

我们运行测试。

在本教程中,我们展示了如何使用SpringRunner在 Spring 应用中创建测试。 Spring MockMvc 教程Spring @PropertySource教程Java 教程

Spring MockMvc 教程

原文: http://zetcode.com/spring/mockmvc/

Spring MockMvc 教程展示了如何使用 MockMvc 测试 Spring MVC 应用。

Spring 是用于创建企业应用的流行 Java 应用框架。

MockMvc

MockMvc被定义为服务器端 Spring MVC 测试的主要入口点。 MockMvc的测试介于单元测试和集成测试之间。

Spring MockMvc 示例

以下应用使用MockMvc测试 Spring MVC 应用。 我们为模板和 RESTful 控制器方法创建测试。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   ├───resources
│   └───webapp
│       └───WEB-INF
│           └───templates
│                   index.html
└───test
    └───java
        └───com
            └───zetcode
                └───controller
                        MyControllerTest.java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>mockmvcex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

        </plugins>
    </build>
</project>

pom.xml文件中,我们具有以下依存关系:logback-classicjavax.servlet-apijunitspring-webmvcspring-testthymeleaf-spring5thymeleaf

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {

        var templateResolver = new SpringResourceTemplateResolver();

        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");

        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {

        var templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);

        return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver() {

        var resolver = new ThymeleafViewResolver();
        var registry = new ViewResolverRegistry(null, applicationContext);

        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);

        return resolver;
    }
}

WebConfig通过@EnableWebMvc启用 Spring MVC 注解,并为com.zetcode包配置组件扫描。 它设置了 Thymeleaf 引擎。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.time.LocalDateTime;

@Controller
public class MyController {

    @GetMapping(value = "/", produces = MediaType.TEXT_HTML_VALUE)
    public String home(Model model) {

        model.addAttribute("now", LocalDateTime.now());

        return "index";
    }

    @GetMapping(value = "/message", produces = MediaType.TEXT_PLAIN_VALUE)
    @ResponseBody
    public String message() {

        return "Hello there!";
    }
}

MyController提供了两种处理器方法。 home()方法返回具有单个属性的视图,message()方法返回纯文本消息。 在我们的测试中,我们测试这两种方法。

WEB-INF/templates/index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>

<p>
Today is: <span th:text="${now}"></span>
</p>

</body>
</html>

这是index.html视图。

com/zetcode/controller/MyControllerTest.java

package com.zetcode.controller;

import org.junit.Before;
import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

public class MyControllerTest {

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.standaloneSetup(new MyController()).build();
    }

    @Test
    public void testHomePage() throws Exception {
        this.mockMvc.perform(get("/"))
                .andExpect(status().isOk())
                .andExpect(view().name("index"))
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
    }

    @Test
    public void testMessagePage() throws Exception {
        this.mockMvc.perform(get("/message")).andExpect(status().isOk())
                .andExpect(content().string("Hello there!"));
    }
}

MyControllerTest测试两个处理器。

private MockMvc mockMvc;

@Before
public void setup() {
    this.mockMvc = MockMvcBuilders.standaloneSetup(new MyController()).build();
}

我们设置了MockMvc。 我们将MyController添加到独立设置中。 MockMvcBuilders.standaloneSetup()允许注册一个或多个控制器,而无需使用完整的WebApplicationContext

@Test
public void testHomePage() throws Exception {
    this.mockMvc.perform(get("/"))
            .andExpect(status().isOk())
            .andExpect(view().name("index"))
            .andDo(MockMvcResultHandlers.print());
}

我们测试主页。 我们验证状态和返回的视图名称。 我们还将打印结果。

@Test
public void testMessagePage() throws Exception {
    this.mockMvc.perform(get("/message")).andExpect(status().isOk())
            .andExpect(content().string("Hello there!"));
}

我们测试消息页面。 由于它是一种 RESTful 方法,因此我们将验证状态和返回的字符串。

$ mvn -q test

我们使用mvn -q test运行测试。

在本教程中,我们使用MockMvc为 Spring MVC 创建了测试。

您可能也对这些相关教程感兴趣: SpringRunner教程Java 教程

Spring @DeleteMapping教程

原文: http://zetcode.com/spring/deletemapping/

Spring @DeleteMapping教程展示了如何使用@DeleteMapping注解将 HTTP DELETE 请求映射到特定的处理器方法。

Spring 是用于创建企业应用的流行 Java 应用框架。

@DeleteMapping

@DeleteMapping注解将 HTTP DELETE 请求映射到特定的处理器方法。 它是一个组合的注解,用作@RequestMapping(method = RequestMethod.DELETE)的快捷方式。

Spring @DeleteMapping示例

以下应用使用@DeleteMapping删除资源。 我们使用注解来设置 Spring Web 应用。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           ├───controller
│   │           │       MyController.java
│   │           ├───model
│   │           │       Post.java
│   │           └───service
│   │                   PostService.java
│   └───resources
│           logback.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>postmappingex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

pom.xml文件中,我们具有项目依赖项。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig {

}

WebConfig通过@EnableWebMvc启用 Spring MVC 注解,并为com.zetcode包配置组件扫描。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import com.zetcode.model.Post;
import com.zetcode.service.IPostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.Set;

import static org.springframework.http.ResponseEntity.ok;

@Controller
public class MyController {

    @Autowired
    private IPostService postService;

    @GetMapping(value="/posts")
    public ResponseEntity<Set<Post>> all() {
        return ok().body(postService.all());
    }

    @DeleteMapping(value = "/posts/{id}")
    public ResponseEntity<Long> deletePost(@PathVariable Long id) {

        var isRemoved = postService.delete(id);

        if (!isRemoved) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }

        return new ResponseEntity<>(id, HttpStatus.OK);
    }
}

MyController提供请求路径和处理器方法之间的映射。 我们有两种映射:一种用于 GET 请求,另一种用于 DELETE 请求。

@GetMapping(value="/posts")
public ResponseEntity<Set<Post>> all() {
    return ok().body(postService.all());
}

@GetMapping注解的方法返回所有帖子。

@DeleteMapping(value = "/posts/{id}")
public ResponseEntity<Long> deletePost(@PathVariable Long id) {

    var isRemoved = postService.delete(id);

    if (!isRemoved) {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }

    return new ResponseEntity<>(id, HttpStatus.OK);
}

deletePost()带有@DeleteMapping注解。 该方法的工作是尝试使用IPostService删除帖子。 根据结果​​返回适当的ResponseEntity

com/zetcode/model/Post.java

package com.zetcode.model;

import java.util.Objects;

public class Post {

    private Long id;
    private String content;

    public Post() {

    }

    public Post(Long id, String content) {
        this.id = id;
        this.content = content;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Post post = (Post) o;
        return Objects.equals(id, post.id) &&
                Objects.equals(content, post.content);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, content);
    }
}

这是一个简单的Post bean。 它具有两个属性:idcontent

com/zetcode/service/IPostService.java

package com.zetcode.service;

import com.zetcode.model.Post;

import java.util.Set;

public interface IPostService {

    boolean delete(Long id);
    Set<Post> all();
}

IPostService包含两种签约方法:delete()all()

com/zetcode/service/PostService.java

package com.zetcode.service;

import com.zetcode.model.Post;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

@Service
public class PostService implements IPostService {

    private final AtomicLong counter = new AtomicLong();

    private final Set<Post> posts = new HashSet<>(Set.of(new Post(counter.incrementAndGet(), "Post one"),
            new Post(counter.incrementAndGet(), "Post two"), new Post(counter.incrementAndGet(), "Post three"),
            new Post(counter.incrementAndGet(), "Post four")));

    public boolean delete(Long id) {

        var isRemoved = this.posts.removeIf(post -> post.getId().equals(id));

        return isRemoved;
    }

    public Set<Post> all() {

        return this.posts;
    }
}

PostService具有删除帖子并返回所有帖子的方法。 我们没有实现数据库层。 相反,我们使用一个简单的内存集合。

注意:在实际应用中,我们还将实现存储库层。

$ mvn jetty:run

我们运行 Jetty 服务器。

$ curl localhost:8080/posts
[{"id":3,"content":"Post three"},{"id":4,"content":"Post four"},
{"id":1,"content":"Post one"},{"id":2,"content":"Post two"}]

使用curl工具,我们可以检索所有帖子。

$ curl -i -X DELETE localhost:8080/posts/1/
HTTP/1.1 200 OK
Date: Wed, 01 May 2019 12:59:07 GMT
Content-Type: application/json;charset=utf-8
Transfer-Encoding: chunked
Server: Jetty(9.4.14.v20181114)

1

我们删除 ID 为 1 的信息。

$ curl localhost:8080/posts
[{"id":3,"content":"Post three"},{"id":4,"content":"Post four"},{"id":2,"content":"Post two"}]

我们又收到了所有帖子。 编号为 1 的帖子已删除。

在本教程中,我们介绍了@DeleteMapping注解。

您可能也对这些相关教程感兴趣: Spring @GetMapping教程Spring @PostMapping教程Spring @RequestMapping教程Spring @MatrixVariable教程Java 教程或列出所有 Spring 教程

Spring @RequestMapping教程

原文: http://zetcode.com/spring/requestmapping/

Spring @RequestMapping教程显示了如何在 Spring Web 应用中使用@RequestMapping注解。 注解用于将 Web 请求映射到请求处理类中的处理器方法上。

Spring 是用于创建企业应用的流行 Java 应用框架。

@RequestMapping

@RequestMapping用于将 Web 请求映射到请求处理类中的处理器方法上。 将 Web 请求映射到处理器方法的过程也称为路由。

@RequestMapping具有以下特化:

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping
  • @PatchMapping

注释可以在类和方法级别上使用。 如果在两个级别上都使用,则将请求路径合并。

Spring @RequestMapping示例

在下面的示例中,我们演示@RequestMapping注解的用法。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   │                   TestController.java
│   └───resources
│           index.html
│           logback.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>RequestMappingEx</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>    

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

pom.xml中,我们具有项目依赖项。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

这是logback.xml配置

resources/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>

<p>
    This is home page.
</p>

</body>
</html>

这是一个主页。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer初始化 Spring Web 应用。 它包含一个配置类:WebConfig

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

WebConfig配置 Spring Web 应用。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalTime;

@RestController
public class MyController {

    @RequestMapping(value = "/")
    public String home() {

        return "This is Home page";
    }

    @RequestMapping(value = "/about", method = RequestMethod.POST)
    public String about() {

        return "This is About page; POST request";
    }

    @RequestMapping(value = "/fresh", method = {RequestMethod.POST, RequestMethod.GET})
    public String fresh() {

        return "This is Fresh page; GET/POST request";
    }

    @RequestMapping(value = "/todo", consumes = "text/plain")
    public String todo() {

        return "This is Todo page; text/plain content type";
    }

    @RequestMapping(value = "/time", params = { "info=time" })
    public String showTime() {

        var now = LocalTime.now();

        return String.format("%s", now.toString());
    }
}

MyController具有@RequestMapping的各种路由定义。

@RequestMapping(value = "/")
public String home() {

    return "This is Home page";
}

使用value选项,我们将/请求路径映射到home()处理器方法。 如果未明确指定,则默认请求方法为 GET。 valuepath选项的别名。

@RequestMapping(value = "/about", method = RequestMethod.POST)
public String about() {

    return "This is About page; POST request";
}

使用method选项,我们可以将处理器映射范围缩小到具有/about路径的 POST 请求。

@RequestMapping(value = "/fresh", method = {RequestMethod.POST, RequestMethod.GET})
public String fresh() {

    return "This is Fresh page; GET/POST request";
}

此方法可以接受 GET 和 POST 请求。

@RequestMapping(value = "/todo", consumes = "text/plain")
public String todo() {

    return "This is Todo page; text/plain content type";
}

使用consumes选项,我们可以将映射范围缩小到具有定义的内容类型的请求。

@RequestMapping(value = "/time", params = { "info=time" })
public String showTime() {

    var now = LocalTime.now();

    return String.format("%s", now.toString());
}

使用params选项,我们可以缩小到/time路径和info=time请求参数的 GET 请求的映射。

com/zetcode/controller/TestController.java

package com.zetcode.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value="/test")
public class TestController {

    @RequestMapping(value = "/info")
    public String info() {

        return "This is info page";
    }

    @RequestMapping(path="*.do")
    public String somePage() {

        return "This is some page";
    }
}

TestController具有另外两个映射。

@RestController
@RequestMapping(value="/test")
public class TestController {

我们也可以将@RequestMapping放在类上。 然后将路径与方法路径合并。

@RequestMapping(value = "/info")
public String info() {

    return "This is info page";
}

该处理器映射到/test/info路径。

@RequestMapping(path="*.do")
public String somePage() {

    return "This is some page";
}

path选项等效于value。 它可以接受 Ant 样式的 URL 映射。

$ mvn jetty:run    

我们运行 Jetty 服务器。

$ curl localhost:8080
This is Home page

我们使用curl工具向主页生成 GET 请求。

$ curl -X POST localhost:8080/about
This is About page; POST request

这是对/about路径的 POST 请求。

$ curl -X POST localhost:8080/fresh
This is Fresh page; GET/POST request
$ curl -X GET localhost:8080/fresh
This is Fresh page; GET/POST request

/fresh页面接受 GET 和 POST 请求。

$ curl -d "info=time" localhost:8080/time
13:24:29.934670700

我们将带有参数的请求发送到/time页面。

$ curl localhost:8080/test/info
This is info page

类级别和方法级别的注解被组合到/test/info路径中。

$ curl localhost:8080/test/produce.do
This is some page

最后是蚂蚁风格的映射。

在本教程中,我们使用@RequestMapping注解创建了各种路径。

您可能也对这些相关教程感兴趣: Spring WebJars 教程Spring @GetMapping教程Spring DefaultServlet教程Spring Web 应用简介Java 教程

Spring @PathVariable教程

原文: http://zetcode.com/spring/pathvariable/

Spring @PathVariable教程显示了如何读取带有@PathVariable注解的 URL 模板变量。 我们创建一个 Spring RESTful 应用来演示注解。

Spring 是用于创建企业应用的流行 Java 应用框架。

@PathVariable

@PathVariable是 Spring 注解,指示方法参数应绑定到 URI 模板变量。 如果方法参数为Map<String, String>,则将使用所有路径变量名称和值填充映射。

它具有以下可选元素:

  • name - 要绑定到的路径变量的名称
  • required - 指示路径变量是否为必需
  • value - 名称的别名

Spring @PathVariable示例

以下示例创建一个使用@PathVariable的 Spring Web 应用。 记录变量值。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
│           logback.xml
└───test
    └───java

这是 Spring 应用的项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>pathvariableex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

我们声明项目依赖项。 @PathVariable来自spring-webmvc封装。

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

DispatcherServlet是 Spring Web 应用的前端控制器,已注册在MyWebInitializer中。

@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[]{WebConfig.class};
}

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig {

}

WebConfig通过@EnableWebMvc启用 Spring MVC 注解,并为com.zetcode包配置组件扫描。

com/zetcode/MyController.java

package com.zetcode.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class MyController {

    private static final Logger logger = LoggerFactory.getLogger(MyController.class);

    @ResponseStatus(value = HttpStatus.OK)
    @GetMapping(value = "/user/{name}")
    public void process(@PathVariable String name) {

        logger.info("User name: {}", name);
    }

    @ResponseStatus(value = HttpStatus.OK)
    @GetMapping(value = "/user/{name}/{email}")
    public void process2(@PathVariable String name, @PathVariable String email) {

        logger.info("User name: {} and email: {}", name, email);
    }

    @ResponseStatus(value = HttpStatus.OK)
    @GetMapping(value = "/book/{author}/{title}")
    public void process3(@PathVariable Map<String, String> vals) {

        logger.info("{}: {}", vals.get("author"), vals.get("title"));

    }
}

我们为 GET 请求提供了三个映射。

@ResponseStatus(value = HttpStatus.OK)
@GetMapping(value = "/user/{name}")
public void process(@PathVariable String name) {

    logger.info("User name: {}", name);
}

在此代码中,URI 模板变量绑定到name方法参数。

@ResponseStatus(value = HttpStatus.OK)
@GetMapping(value = "/user/{name}/{email}")
public void process2(@PathVariable String name, @PathVariable String email) {

    logger.info("User name: {} and email: {}", name, email);
}

通过指定多个@PathVariable注解,也可以绑定多个变量。

@ResponseStatus(value = HttpStatus.OK)
@GetMapping(value = "/book/{author}/{title}")
public void process3(@PathVariable Map<String, String> vals) {

    logger.info("{}: {}", vals.get("author"), vals.get("title"));
}

也可以使用Map<String, String>绑定多个变量。

$ mvn jetty:run

我们启动 Jetty 服务器。

$ curl localhost:8080/user/Peter/peter@gmail.com/

我们用curl发出请求。

22:04:35.273 INFO  com.zetcode.controller.MyController - User name: Peter and email: peter@gmail.com

应用记录此消息。

在本教程中,我们使用 Spring 框架创建了一个 RESTful Web 应用。 我们已经演示了@PathVariable的用法。 您可能也对相关教程感兴趣: Spring @RequestMapping教程Spring @RequestHeader教程Java 教程或列出所有 Spring 教程

Spring @RequestBody教程

原文: http://zetcode.com/spring/requestbody/

Spring @RequestBody教程展示了如何使用@RequestBody注解将方法参数绑定到请求主体。

Spring 是用于创建企业应用的流行 Java 应用框架。

Spring @RequestBody

@RequestBody注解将请求主体绑定到方法参数。 序列化/反序列化的过程由HttpMessageConverter执行。 另外,可以通过使用@Valid注解自变量来应用自动验证。

Spring @RequestBody示例

该应用将表单 POST 和 JSON post 请求的请求主体参数绑定到映射的方法参数。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───bean
│   │           │       User.java
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
│           logback.xml
└───test
    └───java

这是项目结构。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springrequestbodyex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

我们声明必要的依赖关系。 在HttpMessageConverter中进行序列化需要jackson-databind。 该应用在嵌入式 Jetty 上运行; 因此,我们声明jetty-maven-plugin

resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <logger name="org.springframework" level="ERROR"/>
    <logger name="com.zetcode" level="INFO"/>

    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
            </Pattern>
        </encoder>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root>
</configuration>

logback.xml是 Logback 日志库的配置文件。

com/zetcode/bean/User.java

package com.zetcode.bean;

public class User {

    private String name;
    private String occupation;

    public User() {
    }

    public User(String name, String occupation) {
        this.name = name;
        this.occupation = occupation;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getOccupation() {
        return occupation;
    }

    public void setOccupation(String occupation) {
        this.occupation = occupation;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("User{");
        sb.append("name='").append(name).append('\'');
        sb.append(", occupation='").append(occupation).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

在示例中,我们具有User bean,它具有nameoccupation属性。

com/zetcode/config/MyWebInitializer.java

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {

        return new String[]{"/"};
    }
}

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

com/zetcode/config/WebConfig.java

package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

}

WebConfig通过@EnableWebMvc启用 Spring MVC 注解,并为com.zetcode包配置组件扫描。

com/zetcode/controller/MyController.java

package com.zetcode.controller;

import com.zetcode.bean.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    private static final Logger logger = LoggerFactory.getLogger(MyController.class);

    @ResponseStatus(value = HttpStatus.OK)
    @PostMapping(value="/vals")
    public void process(@RequestBody MultiValueMap<String, String> values) {

        logger.info("Values:{}", values);
    }

    @ResponseStatus(value = HttpStatus.OK)
    @PostMapping(value="/user", consumes = MediaType.APPLICATION_JSON_VALUE)
    public void process2(@RequestBody User user) {

        logger.info("User: {}", user);
    }
}

MyContoller中,我们有两个 POST 映射。 我们使用@RequestBody将请求参数绑定到MultiValueMapUser bean。 绑定值显示在日志中。

$ mvn jetty:run

我们启动服务器。

$ curl -i -d "par1=val1&par2=val2" -X POST http://localhost:8080/vals

使用curl工具,我们可以创建第一个映射的请求。 这将创建一个表单 POST 数据请求(内容类型为application/x-www-form-urlencoded)。

11:57:39.049 INFO  com.zetcode.controller.MyController - Values:{par1=[val1], par2=[val2]}

我们得到这个日志。

$ curl -i -H "Content-Type: application/json"  -d "{\"name\":\"John Doe\",\"occupation\":\"gardener\"}" -X POST "http://localhost:8080/user"

我们调用第二个映射。 在这里,我们使用 JSON 数据创建一个请求。 请注意,在 Windows 上,我们需要转义双引号。

12:02:33.817 INFO  com.zetcode.controller.MyController - User: User{name='John Doe', occupation='gardener'}

这是日志中的输出。

在本教程中,我们使用@RequestBody注解将请求属性绑定到方法参数。

您可能也对这些相关教程感兴趣: Spring @PostMapping教程Java 教程或列出所有 Spring 教程

posted @ 2024-10-24 18:18  绝不原创的飞龙  阅读(2)  评论(0编辑  收藏  举报