5.嵌入式 Jetty容器-SpringMVC

image.png

一、接口设计

我们将会在系统中实现两个接口:

GET http://localhost:8888/hello

GET http://localhost:8888/hello/way

其中,第一个接口“/hello”将会返回“Hello World!” 的字符串;而第二个接口“/hello/way”则会返回一个包含用户信息的JSON字符串。

二、系统配置

我们需要在应用中添加如下依赖:

<dependency>
    <groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
    <groupId>org.eclipse.jetty</groupId>
	<artifactId>jetty-servlet</artifactId>
	<scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
	<artifactId>javax.servlet-api</artifactId>
	<scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
</dependency>
复制代码

其中,

spring-webmvc是为了使用 Spring MVC 的功能

jetty-servlet 是为了提供内嵌的 Servlet 容器,这样我们就无需依赖外部的容器,可以直接运行我们的应用。

jackson-core 和 `jackson-databind’为我们的应用提供 JSON 序列化的功能。

三、后台编码实现

领域模型

创建一个 User 类,代表用户信息。

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class User {

    private String username;
	
    private Integer age;
}
复制代码

控制器

创建 HelloController 用于处理用户的请求。

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello() {
        return "Hello World!";
    }

    @RequestMapping("/hello/way")
    public User helloWay() {
        return new User("luopeng", 30);
    }
}
复制代码

其中,映射到“/hello”的方法将会返回“Hello World!” 的字符串;而映射到“/hello/way”则会返回一个包含用户信息的JSON字符串

应用配置

在本应用中,我们采用基于 Java 注解的配置。

AppConfiguration 是我们的主应用配置:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@ComponentScan(basePackages = { "com.epom" })  
@Import({ MvcConfiguration.class })
public class AppConfiguration {

}
复制代码

AppConfiguration 会扫描“com.waylau.spring”包下的文件,并自动将相关的 bean 进行注册。

AppConfiguration 同时又引入了 MVC 的配置类 MvcConfiguration:

import java.util.List;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@EnableWebMvc
@Configuration
public class MvcConfiguration implements WebMvcConfigurer {

    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MappingJackson2HttpMessageConverter());
    }
}
复制代码

MvcConfiguration 配置类一方面启用了 MVC 的功能,另一方面添加了 Jackson JSON 的转换器。

最后,我们需要引入 Jetty 服务器 JettyServer:

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import com.epom.web.AppConfiguration;

public class JettyServer {

	private static final int DEFAULT_PORT = 8888;
	private static final String CONTEXT_PATH = "/";
	private static final String MAPPING_URL = "/*";

	public void run() throws Exception {
		Server server = new Server(DEFAULT_PORT);
		server.setHandler(servletContextHandler(webApplicationContext()));
		server.start();
		server.join();
	}

	private ServletContextHandler servletContextHandler(WebApplicationContext context) {
		ServletContextHandler handler = new ServletContextHandler();
		handler.setContextPath(CONTEXT_PATH);
		handler.addServlet(new ServletHolder(new DispatcherServlet(context)), MAPPING_URL);
		handler.addEventListener(new ContextLoaderListener(context));
		return handler;
	}

	private WebApplicationContext webApplicationContext() {
		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
		context.register(AppConfiguration.class);
		return context;
	}
}
复制代码

JettyServer 将会在 Application 类中进行启动:

public class Application {

	public static void main(String[] args) throws Exception {
        new JettyServer().run();;
    }
}
复制代码

四、运行

2019-12-18 11:18:35.637:INFO::main: Logging initialized @140ms to org.eclipse.jetty.util.log.StdErrLog
2019-12-18 11:18:35.731:INFO:oejs.Server:main: jetty-9.4.22.v20191022; built: 2019-10-22T13:37:13.455Z; git: b1e6b55512e008f7fbdf1cbea4ff8a6446d1073b; jvm 1.8.0_191-b12
2019-12-18 11:18:35.762:INFO:oejshC.ROOT:main: Initializing Spring root WebApplicationContext
十二月 18, 2019 11:18:35 上午 org.springframework.web.context.ContextLoader initWebApplicationContext
信息: Root WebApplicationContext: initialization started
十二月 18, 2019 11:18:36 上午 org.springframework.web.context.ContextLoader initWebApplicationContext
信息: Root WebApplicationContext initialized in 501 ms
2019-12-18 11:18:36.263:INFO:oejshC.ROOT:main: Initializing Spring DispatcherServlet 'org.springframework.web.servlet.DispatcherServlet-62043840'
十二月 18, 2019 11:18:36 上午 org.springframework.web.servlet.FrameworkServlet initServletBean
信息: Initializing Servlet 'org.springframework.web.servlet.DispatcherServlet-62043840'
十二月 18, 2019 11:18:36 上午 org.springframework.web.servlet.FrameworkServlet initServletBean
信息: Completed initialization in 5 ms
2019-12-18 11:18:36.283:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@2631f68c{/,null,AVAILABLE}
2019-12-18 11:18:36.383:INFO:oejs.AbstractConnector:main: Started ServerConnector@368239c8{HTTP/1.1,[http/1.1]}{0.0.0.0:8888}
2019-12-18 11:18:36.383:INFO:oejs.Server:main: Started @888ms
复制代码

分别在浏览器中访问 “http://localhost:8888/hello” 和 “http://localhost:8888/hello/way” 地址进行测试,能看到图1和图2的响应效果。

image.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享