飞道的博客

SpringBoot搭建一个简单的天气预报系统(一)

317人阅读  评论(0)

1. 前言

        先用SpringBoot搭建一个简单的单体项目,后期,再用SpringCluod把它改造一个微服务架构的项目。其实,写这篇博客的真实原因也就学习一下SpringCloud。从单体架构过渡到微服务架构,可以深刻地体会到这两者架构的区别。而且,从今后的发展来看,确实很有必要接触微服务架构

2. 数据来源

        获取预报天气的数据来源:调用第三方接口进行获取。网上有很多免费的天气预报接口,随便找找就有了,也可推荐一个高德地图的天气预报接口,它只能根据城市ID获取天气信息,但它还有个接口“行政区域查询”----可以将城市名称转换为城市ID,我觉得比较麻烦,就放弃了。这里是使用了一个不知名的接口:

  1. 根据城市名获取天气信息:http://wthrcdn.etouch.cn/weather_mini?city=深圳
  2. 根据城市ID取天气信息:http://wthrcdn.etouch.cn/weather_mini?citykey=101280601

        获取城市列表的json文件

3. 实战

        因为此项目是以SpringBoot为基础进行搭建的,所以,建议有SpringBoot基础的读者再看。

项目结构

项目依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <!-- httpclient -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.2</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

3.1 开发环境

  • IDEA:2018.2(安装lombok插件)
  • JDK:8
  • MAVEN:3.6.0
  • SpringBoot:2.3.0

3.2 功能需求

  1. 通过城市ID获取天气信息
  2. 通过城市名称获取天气信息

这两个功能可以通过调用第三方接口进行实现

3.3 手动编码

将接口返回的Json数据进行抽象、封装成Java对象,方便开发人员操作

3.3.1 vo层


WeatherResponseVO:

@Data
public class WeatherResponseVO implements Serializable {
    private static final long serialVersionUID = -8483256225271502962L;
    private WeatherVO data;
    private Integer status;
    private String desc;
}
  1. @Data注解:可以省略对象的set()/get()方法。@Data注解 与 lombok
  2. 实现Serializable 接口:因为这些Java对象要通过网络传输,所以,要序列化

WeatherVO:

@Data
public class WeatherVO implements Serializable {
    private static final long serialVersionUID = 4089597935549696545L;
    private String city;
    private String ganmao;
    private String wendu;
    private YesterdayVO yesterday;
    private List<ForecastVO> forecast;
}

YesterdayVO:

@Data
public class YesterdayVO implements Serializable {
    private static final long serialVersionUID = -806309024676977591L;
    private String date;
    private String high;
    private String fx;
    private String low;
    private String fl;
    private String type;
}

ForecastVO:

@Data
public class ForecastVO implements Serializable {
    private static final long serialVersionUID = 1686655601208573654L;
    private String date;
    private String high;
    private String fengli;
    private String low;
    private String fengxiang;
    private String type;
}

3.3.2 service层

        此层是面向接口开发

WeatherDataService:

public interface WeatherDataService {
    // 根据城市id查询天气数据
    WeatherResponseVO getDataByCityId(String cityId);

    // 根据城市名称查询天气数据
    WeatherResponseVO getDataByCityName(String cityName);
}

WeatherDataServiceImpl:

@Service
public class WeatherDataServiceImpl implements WeatherDataService {
    private static final String WEATHER_URL = "http://wthrcdn.etouch.cn/weather_mini?";

    @Autowired
    private RestTemplate restTemplate;
    
    @Override
    public WeatherResponseVO getDataByCityId(String cityId) {
        String uri = WEATHER_URL + "citykey=" + cityId;
        return doGetWeather(uri, WeatherResponseVO.class);
    }

    @Override
    public WeatherResponseVO getDataByCityName(String cityName) {
        String uri = WEATHER_URL + "city=" + cityName;
        return doGetWeather(uri, WeatherResponseVO.class);
    }
}
  1. 由于两个方法中都使用到了部分相同的uri,所以可以提取相同的uri作为静态常量
  2. RestTemplate:用于HTTP通信。使用HttpClien进行http通信,代码复杂,还得手动资源回收等。Springboot — 用更优雅的方式发HTTP请求(RestTemplate详解)
  3. 由于两个方法中都是通过RestTemplate进行http通信,并将返回的json数据转换为java对象,所以,便可将相同的代码进行抽取为一个共同的方法(重构)

doGetWeather():

private <T> T doGetWeather(String uri, Class<T> type) {
    String key = uri;
    String strBody = null;
    ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
    if (StatusCodeConstant.OK == responseEntity.getStatusCodeValue()) {
        strBody = responseEntity.getBody();
    }
    ObjectMapper objectMapper = new ObjectMapper();
    T t = null;
    try {
        t = objectMapper.readValue(strBody, type);
    } catch (Exception e) {
        log.error("Error!", e);
    }
    return t;
}
  1. 使用了 objectMapper.readValue()方法将json字符串转换为java对象(json字符串中的key要与对象的属性名及类型相对应)
  2. 返回值使用了泛型

3.3.3 controller层

WeatherController:

@RestController
@RequestMapping("/weather")
public class WeatherController {

    @Autowired
    private WeatherDataService weatherDataService;

    @GetMapping("/cityId/{cityId}")
    public WeatherResponseVO getWeatherByCityId(@PathVariable("cityId") String cityId) {
        return weatherDataService.getDataByCityId(cityId);
    }

    @GetMapping("/cityName/{cityName}")
    public WeatherResponseVO getWeatherByCityName(@PathVariable("cityName") String cityName) {
        return weatherDataService.getDataByCityName(cityName);
    }
}

3.3.4 配置类

@Configuration
public class RestConfig {

    @Autowired
    private RestTemplateBuilder builder;

    @Bean
    public RestTemplate restTemplate() {
        return builder.build();
    }
}

        配置RestTemplate:在启动时,RestTemplate会在classpath查找中有哪些依赖,因为已添加HttpClient依赖,所以,RestTemplate会默认把它作为默认的实现

3.3.5 测试

        启动main()方法,在浏览器中访问controller层的接口

1)、根据城市ID获取天气信息

2)、根据城市名称获取天气信息

好了,这两个功能已经实现了。接下来就对它进行简单地优化了。


转载:https://blog.csdn.net/Lucky_Boy_Luck/article/details/106475477
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场