前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >How To Do It - HelloWorld 项目总结报告

How To Do It - HelloWorld 项目总结报告

作者头像
老码农
发布2019-03-12 15:34:32
8500
发布2019-03-12 15:34:32
举报
文章被收录于专栏:老码农专栏

1. 介绍

HelloWorld 是一个HowToDoIt 组织的第一个项目, 一个简单的 MVC 展示应用. 实现项目需要响应发送到 GET / 端点的请求并显示一个主页

  1. 显示 Hello World - 其中 World 可以被 who 查询参数的值替代
  2. [可选] 显示应用版本
  3. [可选] 显示框架版本
  4. [可选] 使用模板引擎生成主页

2. 实现

下面是所有参与项目的链接:

3. 源码一览

3.1 ActFramework

代码语言:javascript
复制
public class AppEntry {

    /**
     * The home (`/`) endpoint.
     *
     * @param who
     *      request query parameter to specify the hello target.
     *      default value is `World`.
     */
    @GetAction
    public void home(@DefaultValue("World") @Output String who) {}

    public static void main(String[] args) throws Exception {
        Act.start();
    }

}

ActFramework 的实现相当简单, 使用了一个类来启动并响应请求.

ActFramework 使用 Rythm 模板引擎生成主页

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
@args String who
<head>
  <title>Hello World - ActFramework</title>
</head>
<body>
  <h1>Hello @who</h1>
  <div>@act.Act.appVersion().getVersion()</div>
  <p>
    Powered by ActFramework @act.Act.VERSION.getVersion()
  </p>
</body>
</html>

ActFramwork 项目实现了所有的需求, 包括可选项.

值得注意的是 ActFramework 使用了 osgl-version 来管理应用版本, 无需编码即可直接从项目的 pom.xml 定义中拿到版本号, 对应用开发来说非常便利: 直接使用 Act.appVersion() 即可拿到应用定义在 pom.xml 文件的版本号. 作为比较, 获得 ActFramework 框架版本号的方法是访问 Act.VERSION 常量.

ActFramework 实现提供的独特优势: 使用 yaml 文件实现了端到端自动化测试.

代码语言:javascript
复制
Scenario(Hello World):
  description: a web page says Hello
  interactions:
    - description: send request to the app without parameter
      request:
        method: GET
        url: /
      response:
        html:
          h1: Hello World
          head title:
            - contains: Hello World
            - contains: ActFramework
          p:
            <any>:
              - contains: Powered by ActFramework
    - description: send request to the app with [who = ActFramework]
      request:
        method: GET
        url: /?who=ActFramework
      response:
        html:
          h1: Hello ActFramework

3.2 Blade

代码语言:javascript
复制
public class Application {

    private static void index(RouteContext ctx) {

        String message = "Hello " + ctx.request().query("who", "World");

        ctx.attribute("message", message);
        ctx.attribute("appVersion", WebContext.blade().env("app.version", "default version"));
        ctx.attribute("bladeVersion", Const.VERSION);
        ctx.render("index.html");
    }

    public static void main(String[] args) {
        Blade.of()
                .get("/", Application::index)
                .start(Application.class, args);
    }

}

Blade 也使用了一个 Java 源码就实现了所有的特性, 代码非常优雅. Blade 使用了类似 velocity 的模板引擎生成主页:

代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
    <h1>${message}</h1>
    Build By ${name} ${version}
</body>
</html>

和 ActFramework 的实现不同, Blade 没有从 pom.xml 文件中获取应用版本信息, 而是在额外的配置文件中定义应用版本.

3.3 JFinal

代码语言:javascript
复制
public class HellWorldController extends Controller {
	public void index(@Para(value="who", defaultValue="World")String who){
		setAttr("who",who).render("index.html");
	}
}
代码语言:javascript
复制
public class ProjectConfig extends JFinalConfig{

	public static void main(String[] args) {
        JFinal.start("src/main/webapp", 8000, "/");
    }
	
	public void configRoute(Routes me) {
		me.setBaseViewPath("/WEB-INF/views").add("/", HellWorldController.class);
	}
	
	public void configConstant(Constants me) {
	}

	public void configEngine(Engine me) {
	}

	public void configPlugin(Plugins me) {
	}

	public void configInterceptor(Interceptors me) {
	}

	public void configHandler(Handlers me) {
	}
}

JFinal 使用了两个 Java 文件, 其中的 Controller 类非常简洁. 不过额外的 ProjectConfig.java 类让整个项目看上去就稍稍繁复了一点点.

JFinal 使用自己的 Enjoy 模板引擎生成主页:

代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HelloWorld</title>
</head>
<body>
<h1>Hello,#(who ?? 'UNKNOWN')!!^_^</h1>
<form action="/">
        <fieldset>
            <legend>Say Hello To The World</legend>
            <div>who: <input type="text" name="who"/></div>
            <input type="submit" value="==问好==">
          </fieldset>
        </body>
</form>
<div style="text-align:center;color:red;padding:10px;">Power By JFinal#(com.jfinal.core.Const::JFINAL_VERSION)</div>
</html>

JFinal 提供了框架版本号,但没有提供应用版本号

3.4 Nutz

代码语言:javascript
复制
@IocBean
public class MainLauncher {
    
    @Inject
    protected PropertiesProxy conf;

    @At("/")
    @Ok("jst:/index.html")
    public NutMap index(String who) throws IOException {
        NutMap re = new NutMap();
        re.put("who", Strings.sBlank(who, "world"));
        re.put("self_version", conf.get("app.build.version", "未知"));
        re.put("nutz_version", Nutz.version());
        return re;
    }

    public static void main(String[] args) throws Exception {
        new NbApp().run();
    }

}

Nutz 的实现和 Blade/ActFramwork 一样都是一个文件解决问题. Nutz 也从 pom.xml 文件中获取项目版本号.

Nutz's 用来生成主页的模板代码:

代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello ${=obj.who}</title>
</head>
<body>
<h1>Hello ${=obj.who}!</h1>
<h3>Self Version: ${obj.self_version}</h3>
<h3>Nutz Version: ${obj.nutz_version}</h3>
</body>
</html>

3.5 Play

代码语言:javascript
复制
@Singleton
class HomeController @Inject()(cc: ControllerComponents, config: Configuration) extends AbstractController(cc) {
  val version = config.get[String]("version")

  def index(who: String) = Action {
    Ok(views.html.index(who, version, PlayVersion.current))
  }

}

和其他所有实现不一样, Play 使用的是 Scala. 代码看上去非常少, 不过对我这个 Javaer 来说还是稍微有点眼生的感觉. Play 的实现也包括了展现 app 和框架版本号, play 没有使用定义在 sbt 脚步中的版本, 而是从 app 配置文件中获取版本号, 稍稍重复了一点.

Play 用来生成页面的模板有两个文件:

代码语言:javascript
复制
@(title: String)(content: Html)

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>@title</title>
    </head>
    <body>
        @content
    </body>
</html>
代码语言:javascript
复制
@(who: String, version: String, playVersion: String)

@main("Hello World - Play"){
<h1>Hello @who</h1>
<div>@version</div>
<p>
 Powered by Play @playVersion
</p>
}

Play 实现提供了自动化测试方案:

代码语言:javascript
复制
class UnitSpec extends PlaySpec with Results {

  "HomeController" should {

    "return a valid result with action" in {
      val config = Configuration(ConfigFactory.load("application"))
      val controller = new HomeController(stubControllerComponents(), config)
      val result = controller.index("world")(FakeRequest())
      status(result) mustEqual OK
      contentAsString(result) must include ("Hello World")
    }
  }
}
代码语言:javascript
复制
class FunctionalSpec extends PlaySpec with GuiceOneAppPerSuite {

  "HomeController" should {

    "render the index page" in {
      val home = route(app, FakeRequest(GET, "/?who=World")).get

      status(home) mustBe Status.OK
      contentType(home) mustBe Some("text/html")
      contentAsString(home) must include ("Hello World")
    }

  }
}
代码语言:javascript
复制
class BrowserSpec extends PlaySpec
  with OneBrowserPerTest
  with GuiceOneServerPerTest
  with HtmlUnitFactory
  with ServerProvider {

  "Application" should {

    "work from within a browser" in {

      go to ("http://localhost:" + port)

      pageSource must include ("Hello World")
    }
  }
}

3.6 Redkale

代码语言:javascript
复制
@RestService(name = " ")
public class HelloWorldService implements Service {

    private String appVersion = "1.0.0";

    @Override
    public void init(AnyValue conf) {
        String path = "/META-INF/maven/org.redkalex.htdi/htdi-hello/pom.properties";
        InputStream in = this.getClass().getResourceAsStream(path);
        if (in != null) {
            Properties props = new Properties();
            try {
                props.load(in);
                in.close();
            } catch (Exception e) {
            }
            this.appVersion = props.getProperty("version", "未知");
        }
    }

    @RestMapping(name = "index.html", auth = false)
    public HttpResult<String> index(String who) throws IOException {
        if (who == null || who.isEmpty()) who = "World";
        String body = "<!DOCTYPE html>\n"
            + "<html>\n"
            + "<head>\n"
            + "<meta charset=\"UTF-8\">\n"
            + "<title>Hello " + who + "</title>\n"
            + "</head>\n"
            + "<body>\n"
            + "<h1>Hello " + who + "!</h1>\n"
            + "<h3>Project Version: " + appVersion + "</h3>\n"
            + "<h3>Redkale Version: " + Redkale.getDotedVersion() + "</h3>\n"
            + "</body>\n"
            + "</html>";
        return new HttpResult<>("text/html;charset=utf8", body);
    }

}

Redkale 实现直接使用字串拼接输出而不是模板引擎. 对于 HelloWorld 这样的项目这样做完全没有问题. 不过稍微正式一点的项目这样会死人的吧. Redkale 的作者强调 Redkale 的应用更多偏向于数据服务, 同时也提到如果需要模板引擎应用可以很方便地集成三方产品.

Redkale 实现了展示应用和框架版本的需求.

3.7 SprintBoot

代码语言:javascript
复制
@SpringBootApplication
public class App extends SpringBootServletInitializer implements WebApplicationInitializer {

    public static void main( String[] args )
    {
        SpringApplication.run(App.class, args);
    }
}
代码语言:javascript
复制
@Controller
public class HelloController {
    @RequestMapping("/")
    public ModelAndView sayHello() {
        ModelAndView view = new ModelAndView("/sayHello.html");
        view.addObject("message", "Hello world"); 
        view.addObject("name", "Spring Boot");
        view.addObject("version", "2.x");
        return view;
    }
}

SpringBoot 的实现也很容易理解. 使用了 2 个源代码文件, 一个是启动入口, 另一个是响应处理器.

SprintBoot 使用 Beetl 引擎来生成主页:

代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World</title>
</head>
<body>
	<h1>${message}</h1>
	Build By ${name} ${version}
</body>
</html>

SprintBoot 硬编码了框架版本, 没有显示应用版本.

SprintBoot 实现提供了单元测试.

代码语言:javascript
复制
@RunWith(SpringRunner.class)
@WebMvcTest(HelloController.class)
public class MvcTest{
    @Autowired
    private MockMvc mvc;
    @Test
    public void testHello() throws Exception {
      
        String viewName = mvc.perform(get("/")).andReturn().getModelAndView().getViewName();
        Assert.assertEquals("/sayHello.html", viewName);
    }
}

这个测试条件比较有趣, 检查是否使用了正确的 view 模板, 并没有针对真正的需求进行测试

3.8 TIO-MVC

代码语言:javascript
复制
@RequestPath(value = "/")
public class HelloController {
	@RequestPath(value = "")
	public HttpResponse index(HttpRequest request, String who) throws Exception {
		String name = StrUtil.isBlank(who) ? "World" : who;
		String html = "<title>Hello " + name + "</title><h1>Hello " + name + "</h1>";
		html += "<div>" + HowToDoTioStarter.APP_NAME + " " + P.p.getStr("app.version") + "</div>";
		html += "<div>Powered by <a href='https://t-io.org' target='_blank'>" + HttpConst.SERVER_INFO + " " + SysConst.TIO_CORE_VERSION + "</a></div>";
		return Resps.html(request, html);
	}
}
代码语言:javascript
复制
public class P {
	public static Props p = new Props("classpath:app.properties");
}
代码语言:javascript
复制
public class HowToDoTioStarter {
	public static final String APP_NAME = "how to do it : tio-mvc";
	
	public static HttpConfig httpConfig;

	public static HttpRequestHandler requestHandler;

	public static HttpServerStarter httpServerStarter;

	public static ServerGroupContext serverGroupContext;

	public static void init() throws Exception {
		httpConfig = new HttpConfig(P.p.getInt("http.port"), null, null, null);
//		httpConfig.setPageRoot(P.p.getStr("http.page"));//html/css/js等的根目录,支持classpath:,也支持绝对路径
//		httpConfig.setMaxLiveTimeOfStaticRes(P.p.getInt("http.maxLiveTimeOfStaticRes"));
//		httpConfig.setPage404(P.p.getStr("http.404"));
//		httpConfig.setPage500(P.p.getStr("http.500"));
		httpConfig.setUseSession(false);
		httpConfig.setCheckHost(false);

		String[] scanPackages = new String[] { HelloController.class.getPackage().getName() };//tio mvc需要扫描的根目录包,会递归子目录
		Routes routes = new Routes(scanPackages);
		requestHandler = new DefaultHttpRequestHandler(httpConfig, routes);

		httpServerStarter = new HttpServerStarter(httpConfig, requestHandler);
		serverGroupContext = httpServerStarter.getServerGroupContext();
		serverGroupContext.setUseQueueSend(true);
		httpServerStarter.start(); //启动http服务器
	}
	
	public static void main(String[] args) throws Exception {
		init();
	}
}

TIO-MVC 的实现代码行数和 JFinal 实现相近. 控制器本身的代码相对简单, 只是实现中有一些 boilerplate 代码, 和其他实现比较起来稍显臃肿.

和 Redkale 一样, TIO-MVC 的实现选择使用字串拼接来生成主页; 另外 TIO-MVC 的应用版本是硬编码在代码中的.

4. 启动

4.1 启动 ActFramework

ActFramework 提供了不同脚本来实现不同模式的启动:

4.1.1 开发模式
4.1.2 e2e 测试模式

使用 e2e 模式启动应用可以启动后立刻运行自动化测试脚本:

4.1.3 产品模式

4.2 Blade

Blade 没有提供启动脚本, 不过 README 文件提供了启动步骤

4.3 JFinal

在启动 JFinal 项目的时候我们遇到了一点麻烦, 因为 JFinal build 的包是用来部署到 servlet 容器里面的, 我们不太想去和 Tomcat 之类的东西打交道, 所以在 JFinal 项目里面添加了插件:

代码语言:javascript
复制
		<plugins>
		  <plugin>
		    <groupId>org.mortbay.jetty</groupId>
		    <artifactId>jetty-maven-plugin</artifactId>
		    <version>8.1.8.v20121106</version>
		    <configuration>
		        <stopKey>stop</stopKey>
		        <stopPort>5599</stopPort>
		        <webAppConfig>
		            <contextPath>/</contextPath>
		        </webAppConfig>
		        <scanIntervalSeconds>5</scanIntervalSeconds>
		        <connectors>
		            <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
		                <port>80</port>
		                <maxIdleTime>60000</maxIdleTime>
		            </connector>
		        </connectors>
		    </configuration>
		  </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <executable>java</executable>
                    <arguments>
                        <argument>-Xms512m</argument>
                        <argument>-Xmx512m</argument>
                        <argument>-classpath</argument>
                        <classpath/>
                        <argument>htdi.jfinal.hellworld.config.ProjectConfig</argument>
                    </arguments>
                </configuration>
            </plugin>
	</plugins>

之后我们就可以直接启动了:

4.4 Nutz

Nutz 也是通过 README 文件提供了启动步骤. Nutz 启动信息比较多, 没法截屏:

代码语言:javascript
复制
luog@luog-X510UQR:~/p/htdi/nutz-hello-world$ mvn -q clean compile nutzboot:run
[INFO ] 07:55:50.685 org.nutz.boot.banner.SimpleBannerPrinter.printBanner(SimpleBannerPrinter.java:34) - 
 _   _ ______                                      ___   
| \ | || ___ \  ______ ______ ______ ______ ______| \ \  
|  \| || |_/ / |______|______|______|______|______| |\ \ 
| . ` || ___ \  ______ ______ ______ ______ ______| | > >
| |\  || |_/ / |______|______|______|______|______| |/ / 
\_| \_/\____/                                     |_/_/  
  
:: Nutz Boot ::   (2.3-SNAPSHOT)

[INFO ] 07:55:50.736 org.nutz.ioc.loader.annotation.AnnotationIocLoader.<init>(AnnotationIocLoader.java:50) -  > scan 'htdi.nutz.helloworld'
[INFO ] 07:55:50.738 org.nutz.ioc.loader.annotation.AnnotationIocLoader.addClass(AnnotationIocLoader.java:98) -    > add 'mainLauncher                            ' - htdi.nutz.helloworld.MainLauncher
[INFO ] 07:55:50.740 org.nutz.ioc.loader.annotation.AnnotationIocLoader.<init>(AnnotationIocLoader.java:50) -  > scan 'org.nutz.boot.starter'
[INFO ] 07:55:50.750 org.nutz.ioc.loader.annotation.AnnotationIocLoader.addClass(AnnotationIocLoader.java:98) -    > add 'nutFilterStarter                        ' - org.nutz.boot.starter.nutz.mvc.NutFilterStarter
[INFO ] 07:55:50.753 org.nutz.ioc.loader.annotation.AnnotationIocLoader.addClass(AnnotationIocLoader.java:98) -    > add 'whaleFilterStarter                      ' - org.nutz.boot.starter.nutz.mvc.WhaleFilterStarter
[INFO ] 07:55:50.754 org.nutz.ioc.loader.annotation.AnnotationIocLoader.addClass(AnnotationIocLoader.java:98) -    > add 'jettyStarter                            ' - org.nutz.boot.starter.jetty.JettyStarter
[INFO ] 07:55:50.765 org.nutz.ioc.loader.annotation.AnnotationIocLoader.addClass(AnnotationIocLoader.java:98) -    > add 'nbServletContextListener                ' - org.nutz.boot.starter.servlet3.NbServletContextListener
[INFO ] 07:55:50.767 org.nutz.ioc.loader.annotation.AnnotationIocLoader.addClass(AnnotationIocLoader.java:98) -    > add 'jstViewStarter                          ' - org.nutz.boot.starter.jst.JstViewStarter
[INFO ] 07:55:50.777 org.nutz.boot.NbApp.prepare(NbApp.java:279) - Configure Manual:
|id  |key                                     |required  |Possible Values     |Default   |Description         |                                starters|
|----|----------------------------------------|----------|--------------------|----------|--------------------|----------------------------------------|
|0   |jetty.contextPath                       |no        |                    |/         |上下文路径               |org.nutz.boot.starter.jetty.JettyStarter|
|1   |jetty.gzip.enable                       |no        |                    |false     |是否启用gzip            |org.nutz.boot.starter.jetty.JettyStarter|
|2   |jetty.gzip.level                        |no        |                    |-1        |gzip压缩级别            |org.nutz.boot.starter.jetty.JettyStarter|
|3   |jetty.gzip.minContentSize               |no        |                    |512       |gzip压缩最小触发大小        |org.nutz.boot.starter.jetty.JettyStarter|
|4   |jetty.host                              |no        |                    |0.0.0.0   |监听的ip地址             |org.nutz.boot.starter.jetty.JettyStarter|
|5   |jetty.http.idleTimeout                  |no        |                    |300000    |空闲时间,单位毫秒           |org.nutz.boot.starter.jetty.JettyStarter|
|6   |jetty.httpConfig.blockingTimeout        |no        |                    |-1        |阻塞超时                |org.nutz.boot.starter.jetty.JettyStarter|
|7   |jetty.httpConfig.headerCacheSize        |no        |                    |8192      |头部缓冲区大小             |org.nutz.boot.starter.jetty.JettyStarter|
|8   |jetty.httpConfig.maxErrorDispatches     |no        |                    |10        |最大错误重定向次数           |org.nutz.boot.starter.jetty.JettyStarter|
|9   |jetty.httpConfig.outputAggregationSize  |no        |                    |8192      |输出聚合大小              |org.nutz.boot.starter.jetty.JettyStarter|
|10  |jetty.httpConfig.outputBufferSize       |no        |                    |32768     |输出缓冲区大小             |org.nutz.boot.starter.jetty.JettyStarter|
|11  |jetty.httpConfig.persistentConnectionsEnabled|no        |                    |true      |是否启用持久化连接           |org.nutz.boot.starter.jetty.JettyStarter|
|12  |jetty.httpConfig.requestHeaderSize      |no        |                    |8192      |请求的头部最大值            |org.nutz.boot.starter.jetty.JettyStarter|
|13  |jetty.httpConfig.responseHeaderSize     |no        |                    |8192      |响应的头部最大值            |org.nutz.boot.starter.jetty.JettyStarter|
|14  |jetty.httpConfig.securePort             |no        |                    |          |安全协议的端口,例如8443      |org.nutz.boot.starter.jetty.JettyStarter|
|15  |jetty.httpConfig.secureScheme           |no        |                    |          |安全协议,例如https        |org.nutz.boot.starter.jetty.JettyStarter|
|16  |jetty.httpConfig.sendDateHeader         |no        |                    |true      |是否发送日期信息            |org.nutz.boot.starter.jetty.JettyStarter|
|17  |jetty.httpConfig.sendServerVersion      |no        |                    |true      |是否发送jetty版本号        |org.nutz.boot.starter.jetty.JettyStarter|
|18  |jetty.maxFormContentSize                |no        |                    |1gb       |表单最大尺寸              |org.nutz.boot.starter.jetty.JettyStarter|
|19  |jetty.page.404                          |no        |                    |          |自定义404页面,同理,其他状态码也是支持的|org.nutz.boot.starter.jetty.JettyStarter|
|20  |jetty.page.java.lang.Throwable          |no        |                    |          |自定义java.lang.Throwable页面,同理,其他异常也支持|org.nutz.boot.starter.jetty.JettyStarter|
|21  |jetty.port                              |no        |                    |8080      |监听的端口               |org.nutz.boot.starter.jetty.JettyStarter|
|22  |jetty.staticPath                        |no        |                    |          |额外的静态文件路径           |org.nutz.boot.starter.jetty.JettyStarter|
|23  |jetty.staticPathLocal                   |no        |                    |          |静态文件所在的本地路径         |org.nutz.boot.starter.jetty.JettyStarter|
|24  |jetty.threadpool.idleTimeout            |no        |                    |60000     |线程池idleTimeout,单位毫秒 |org.nutz.boot.starter.jetty.JettyStarter|
|25  |jetty.threadpool.maxThreads             |no        |                    |500       |线程池最大线程数maxThreads  |org.nutz.boot.starter.jetty.JettyStarter|
|26  |jetty.threadpool.minThreads             |no        |                    |200       |线程池最小线程数minThreads  |org.nutz.boot.starter.jetty.JettyStarter|
|27  |jetty.welcome_files                     |no        |                    |index.html,index.htm,index.do|WelcomeFile列表       |org.nutz.boot.starter.jetty.JettyStarter|
|28  |nutz.mvc.whale.enc.input                |no        |                    |UTF-8     |在其他Filter之前设置input编码|org.nutz.boot.starter.nutz.mvc.WhaleFilterStarter|
|29  |nutz.mvc.whale.enc.output               |no        |                    |UTF-8     |在其他Filter之前设置output编码|org.nutz.boot.starter.nutz.mvc.WhaleFilterStarter|
|30  |nutz.mvc.whale.http.hidden_method_param |no        |                    |          |隐形http方法参数转换所对应的参数名 |org.nutz.boot.starter.nutz.mvc.WhaleFilterStarter|
|31  |nutz.mvc.whale.http.method_override     |no        |                    |false     |是否允许使用X-HTTP-Method-Override|org.nutz.boot.starter.nutz.mvc.WhaleFilterStarter|
|32  |nutz.mvc.whale.upload.enable            |no        |                    |false     |是否启用隐形Upload支持      |org.nutz.boot.starter.nutz.mvc.WhaleFilterStarter|
|33  |web.session.timeout                     |no        |                    |30        |Session空闲时间,单位分钟    |org.nutz.boot.starter.jetty.JettyStarter|
[INFO ] 07:55:50.782 org.nutz.ioc.impl.NutIoc.<init>(NutIoc.java:130) - ... NutIoc init complete
[INFO ] 07:55:50.825 org.eclipse.jetty.util.log.Log.initialized(Log.java:193) - Logging initialized @2378ms to org.eclipse.jetty.util.log.Slf4jLog
[INFO ] 07:55:50.987 org.eclipse.jetty.server.Server.doStart(Server.java:374) - jetty-9.4.11.v20180605; built: 2018-06-05T18:24:03.829Z; git: d5fc0523cfa96bfebfbda19606cad384d772f04c; jvm 1.8.0_171-b11
[WARN ] 07:55:51.173 org.eclipse.jetty.annotations.AnnotationParser.asmVersion(AnnotationParser.java:95) - Unknown asm implementation version, assuming version 393216
[INFO ] 07:55:51.173 org.eclipse.jetty.annotations.AnnotationConfiguration.scanForAnnotations(AnnotationConfiguration.java:489) - Scanning elapsed time=0ms
[INFO ] 07:55:51.177 org.eclipse.jetty.webapp.StandardDescriptorProcessor.visitServlet(StandardDescriptorProcessor.java:283) - NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
[INFO ] 07:55:51.185 org.eclipse.jetty.server.session.DefaultSessionIdManager.doStart(DefaultSessionIdManager.java:365) - DefaultSessionIdManager workerName=node0
[INFO ] 07:55:51.185 org.eclipse.jetty.server.session.DefaultSessionIdManager.doStart(DefaultSessionIdManager.java:370) - No SessionScavenger set, using defaults
[INFO ] 07:55:51.187 org.eclipse.jetty.server.session.HouseKeeper.startScavenging(HouseKeeper.java:149) - node0 Scavenging every 660000ms
[INFO ] 07:55:51.202 org.nutz.mvc.NutFilter._init(NutFilter.java:85) - NutFilter[nutz] starting ...
[INFO ] 07:55:51.207 org.nutz.mvc.impl.NutLoading.load(NutLoading.java:55) - Nutz Version : 1.r.66-20180614 
[INFO ] 07:55:51.207 org.nutz.mvc.impl.NutLoading.load(NutLoading.java:56) - Nutz.Mvc[nutz] is initializing ...
[INFO ] 07:55:51.207 org.nutz.mvc.config.AbstractNutConfig.getAppRoot(AbstractNutConfig.java:82) - /WEB-INF/ not Found?!
[INFO ] 07:55:51.210 org.nutz.mvc.impl.NutLoading.evalUrlMapping(NutLoading.java:159) - Build URL mapping by org.nutz.mvc.impl.UrlMappingImpl ...
[INFO ] 07:55:51.232 org.nutz.mvc.impl.NutActionChainMaker.getProcessorByName(NutActionChainMaker.java:72) - Optional processor class not found, disabled : org.nutz.integration.shiro.NutShiroProcessor
[INFO ] 07:55:51.254 org.nutz.mvc.impl.NutActionChainMaker.getProcessorByName(NutActionChainMaker.java:72) - Optional processor class not found, disabled : org.nutz.plugins.validation.ValidationProcessor
[INFO ] 07:55:51.262 org.nutz.mvc.impl.NutLoading.evalUrlMappingluog@luog-X510UQR:~/p/htdi/nutz-hello-world$ mvn -q clean compile nutzboot:run
(NutLoading.java:221) - Found 1 module methods
[INFO ] 07:55:51.263 org.nutz.mvc.impl.NutLoading.load(NutLoading.java:141) - Nutz.Mvc[nutz] is up in 56ms
[INFO ] 07:55:51.277 org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:851) - Started o.e.j.w.WebAppContext@d2b229c{/,[],AVAILABLE}
[INFO ] 07:55:51.288 org.eclipse.jetty.server.AbstractConnector.doStart(AbstractConnector.java:289) - Started ServerConnector@32a11092{HTTP/1.1,[http/1.1]}{127.0.0.1:8080}
[INFO ] 07:55:51.288 org.eclipse.jetty.server.Server.doStart(Server.java:411) - Started @2842ms
[INFO ] 07:55:51.291 org.nutz.boot.NbApp.execute(NbApp.java:213) - NB started : 702ms

4.5 Play

Play 的实现使用了 sbt, 第一次运行简直就是灾难, 花了至少半个小时才能启动. 不过第一次之后就都很好了:

4.6 Redkale

和大部分实现项目一样, Redkale 在 README 中提供了如何启动应用的方法. 我们可以很容易启动 Redkale 项目:

4.7 SpringBoot

启动 SpringBoot 项目没有什么问题:

4.8 TIO-MVC

TIO-MVC 实现稍微有一点不一样. 使用 mvn clean package 构建项目包之后我们需要到 /target/htdi-tio-helloworld 目录然后运行 startup.sh 启动应用:

5. 一些数据比较

注意

1 SpringBoot 提供了单元测试用例, 不过该测试只检查是否加载了正确的模板文件, 并没有检查输出是否满足需求 2 测试环境: 操作系统: LinuxMint 19, 硬件: i7 8550U + 16GB RAM + SSD

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/07/29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 介绍
  • 2. 实现
  • 3. 源码一览
    • 3.1 ActFramework
      • 3.2 Blade
        • 3.3 JFinal
          • 3.4 Nutz
            • 3.5 Play
              • 3.6 Redkale
                • 3.7 SprintBoot
                  • 3.8 TIO-MVC
                  • 4. 启动
                    • 4.1 启动 ActFramework
                      • 4.1.1 开发模式
                      • 4.1.2 e2e 测试模式
                      • 4.1.3 产品模式
                    • 4.2 Blade
                      • 4.3 JFinal
                        • 4.4 Nutz
                          • 4.5 Play
                            • 4.6 Redkale
                              • 4.7 SpringBoot
                                • 4.8 TIO-MVC
                                • 5. 一些数据比较
                                相关产品与服务
                                云服务器
                                云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
                                领券
                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档