7.8. simple-command模块

simple-command项目是simple-webapp的一个命令行版本。这个命令行工具有这同样的模块依赖:simple-persistsimple-weather。现在你需要从命令行运行这个simple-command工具,而非通过web浏览器与该应用交互。

引用 simple-weather 和 simple-persist 的命令行应用

Figure 7.4. 引用 simple-weather 和 simple-persist 的命令行应用


Example 7.19. simple-command 的 POM

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.sonatype.mavenbook.ch07</groupId>
    <artifactId>simple-parent</artifactId>
    <version>1.0</version>
  </parent>

  <artifactId>simple-command</artifactId>
  <packaging>jar</packaging>
  <name>Simple Command Line Tool</name>

  <build>
    <finalName>content-zh</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <testFailureIgnore>true</testFailureIgnore>
        </configuration>
      </plugin>
      <plugin>
       <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>hibernate3-maven-plugin</artifactId>
        <version>2.1</version>
        <configuration>
          <components>
            <component>
              <name>hbm2ddl</name>
              <implementation>annotationconfiguration</implementation>
            </component>
          </components>
        </configuration>
        <dependencies>
          <dependency>
            <groupId>hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>1.8.0.7</version>
          </dependency>
        </dependencies>           
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.sonatype.mavenbook.ch07</groupId>
      <artifactId>simple-weather</artifactId>
      <version>1.0</version>
    </dependency>
    <dependency>
      <groupId>org.sonatype.mavenbook.ch07</groupId>
      <artifactId>simple-persist</artifactId>
      <version>1.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring</artifactId>
      <version>2.0.7</version>
    </dependency>
    <dependency>
      <groupId>hsqldb</groupId>
      <artifactId>hsqldb</artifactId>
      <version>1.8.0.7</version>
    </dependency>
  </dependencies>
</project>

这个POM创建一个包含了如Example 7.20, “simple-command 的 Main 类”所示的org.sonatype.mavenbook.weather.Main类的JAR文件。在这个POM中我们配置了Maven Assembly插件使用内置的名为jar-with-dependencies的装配描述符来创建一个JAR文件,该文件包含了运行应用所需要的所有二进制代码,包括项目本身的字节码以及所有依赖文件的字节码。

Example 7.20. simple-command 的 Main 类

package org.sonatype.mavenbook.weather;

import java.util.List;

import org.apache.log4j.PropertyConfigurator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import org.sonatype.mavenbook.weather.model.Location;
import org.sonatype.mavenbook.weather.model.Weather;
import org.sonatype.mavenbook.weather.persist.LocationDAO;
import org.sonatype.mavenbook.weather.persist.WeatherDAO;

public class Main {

  private WeatherService weatherService;
  private WeatherDAO weatherDAO;
  private LocationDAO locationDAO;

  public static void main(String[] args) throws Exception {
    // Configure Log4J
    PropertyConfigurator.configure(Main.class.getClassLoader().getResource(
        "log4j.properties"));

    // Read the Zip Code from the Command-line (if none supplied, use 60202)
    String zipcode = "60202";
    try {
      zipcode = args[0];
    } catch (Exception e) {
    }

    // Read the Operation from the Command-line (if none supplied use weather)
    String operation = "weather";
    try {
      operation = args[1];
    } catch (Exception e) {
    }

    // Start the program
    Main main = new Main(zipcode);

    ApplicationContext context = 
      new ClassPathXmlApplicationContext(
        new String[] { "classpath:applicationContext-weather.xml",
                       "classpath:applicationContext-persist.xml" });
    main.weatherService = (WeatherService) context.getBean("weatherService");
    main.locationDAO = (LocationDAO) context.getBean("locationDAO");
    main.weatherDAO = (WeatherDAO) context.getBean("weatherDAO");
    if( operation.equals("weather")) {
      main.getWeather();
    } else {
      main.getHistory();
    }
  }

  private String zip;

  public Main(String zip) {
    this.zip = zip;
  }

  public void getWeather() throws Exception {
    Weather weather = weatherService.retrieveForecast(zip);
    weatherDAO.save( weather );
    System.out.print(new WeatherFormatter().formatWeather(weather));
  }

  public void getHistory() throws Exception {
    Location location = locationDAO.findByZip(zip);
    List<Weather> weathers = weatherDAO.recentForLocation(location);
    System.out.print(new WeatherFormatter().formatHistory(location, weathers));
  }
}

这个Main类有对于WeatherDAO, LocationDAO, 以及 WeatherService的引用。该类的静态main()方法:

  • 从第一个命令行参数读取邮编。

  • 从第二个命令行参数读取操作。如果操作是“weather”,最新的天气将会从web服务获得。如果操作是“history”,该程序会从本地数据库获取历史天气记录。

  • 根据来自于simple-persistsimple-weather的两个XML文件载入Spring ApplicationContext

  • 创建一个Main的实例。

  • 使用来自于Spring ApplicationContext的bean填充weatherService, weatherDAO, 和 locationDAO

  • 根据特定的操作运行相应的getWeather()或者getHistory()方法。

在web应用中我们使用Spring VelocityViewResolver来呈现一个Velocity模板。在这个单机实现中给我们需要编写一个简单的类来通过Velocity模板呈现天气数据。Example 7.21, “WeatherFormatter 使用 Velocity 模板呈现天气数据”WeatherFormatter的代码清单,这个类有两个方法来呈现天气报告和天气历史信息。

Example 7.21. WeatherFormatter 使用 Velocity 模板呈现天气数据

package org.sonatype.mavenbook.weather;

import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import org.sonatype.mavenbook.weather.model.Location;
import org.sonatype.mavenbook.weather.model.Weather;

public class WeatherFormatter {

  private static Logger log = Logger.getLogger(WeatherFormatter.class);

  public String formatWeather( Weather weather ) throws Exception {
    log.info( "Formatting Weather Data" );
    Reader reader = 
      new InputStreamReader( getClass().getClassLoader().
                                 getResourceAsStream("weather.vm"));
    VelocityContext context = new VelocityContext();
    context.put("weather", weather );
    StringWriter writer = new StringWriter();
    Velocity.evaluate(context, writer, "", reader);
    return writer.toString();
  }

  public String formatHistory( Location location, List<Weather> weathers )  
        throws Exception {
    log.info( "Formatting History Data" );
    Reader reader = 
      new InputStreamReader( getClass().getClassLoader().
                                 getResourceAsStream("history.vm"));
    VelocityContext context = new VelocityContext();
    context.put("location", location );
    context.put("weathers", weathers );
    StringWriter writer = new StringWriter();
    Velocity.evaluate(context, writer, "", reader);
    return writer.toString();
  }
}

weather.vm模板简单的打印邮编对应的城市,国家,区域以及当前的气温。history.vm模板打印位置信息并遍历存储在本地数据库中的天气预报记录。两者都位于/data/hudson-temporal-data/hudson-orchestrator-home/workspace/Book-To-Production/content-zh/src/main/resources

Example 7.22. weather.vm Velocity 模板

****************************************
Current Weather Conditions for:
  ${weather.location.city},
  ${weather.location.region},
  ${weather.location.country}
****************************************

 * Temperature: ${weather.condition.temp}
 * Condition: ${weather.condition.text}
 * Humidity: ${weather.atmosphere.humidity}
 * Wind Chill: ${weather.wind.chill}
 * Date: ${weather.date}

Example 7.23. history.vm Velocity 模板

Weather History for:
${location.city},
${location.region},
${location.country}


#foreach( $weather in $weathers )
****************************************
 * Temperature: $weather.condition.temp
 * Condition: $weather.condition.text
 * Humidity: $weather.atmosphere.humidity
 * Wind Chill: $weather.wind.chill
 * Date: $weather.date
#end