14、旅游应用中的货币兑换与时间显示功能实现

旅游应用中的货币兑换与时间显示功能实现

1. 货币兑换功能实现

在旅游应用中,显示用户所在国家与远程地点之间的货币汇率是一项重要功能。我们将使用WebserviceX来实现货币兑换,它采用SOAP协议,与之前的方法有所不同。
- 获取货币代码数据 :ISO 4217是定义货币名称的国际标准,由三个字母组成,前两个字母通常是ISO 3166 - 1 alpha 2定义的国家代码,最后一个字母通常是货币本身的首字母。例如,美元是USD,日元是JPY。
1. 访问ISO网站: http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list - 1.htm ,将货币列表复制到电子表格中。
2. 保存为逗号分隔文件(CSV),命名为 currency_codes.csv ,并放置在 RAILS_ROOT/db/migrate 文件夹中。文件内容示例如下:

"AFGHANISTAN","Afghani","AFN"
"ALBANIA","Lek","ALL"
"ALGERIA","Algerian Dinar","DZD"
"AMERICAN SAMOA","US Dollar","USD"
"ANDORRA","Euro","EUR"
  • 创建数据库迁移文件
    1. 生成迁移文件:
$./script/generate migration create_currencies
2. 编辑生成的`001_create_currencies.rb`文件:
class CreateCurrencies < ActiveRecord::Migration
  def self.up
    create_table :currencies do |t|
      t.column :country, :string
      t.column :name, :string
      t.column :code, :string
    end
  end
  def self.down
    drop_table :currencies
  end
end
3. 运行数据库迁移:
$rake db:migrate
  • 创建Currency类 :在 RAILS_ROOT/app/models 文件夹中创建 currency.rb 文件:
class Currency < ActiveRecord::Base
end
  • 填充数据到数据库
    1. 生成另一个迁移文件:
$./script/generate migration currencies_data
2. 编辑生成的`002_currencies_data.rb`文件:
require 'csv'
class CurrenciesData < ActiveRecord::Migration
  def self.up
    down
    CSV.open("#{File.dirname(__FILE__)}/currency_codes.csv", 
             'r') do |row|
      currency = Currency.new({:country => row[0], 
                               :name => row[1], 
                               :code => row[2]})
      currency.save
    end
  end
  def self.down
    Currency.delete_all
  end
end
3. 再次运行数据库迁移。
  • 完善Currency类 :在 currency.rb 文件中完善 Currency 类:
require 'soap/wsdlDriver'
class Currency < ActiveRecord::Base
  WSDL_URL = "http://www.webservicex.net/CurrencyConvertor.asmx?WSDL"
  attr_accessor :amount
  def Currency.get(code)
    Currency.find(:first, 
                  :conditions => ['code = ?', code])
  end
  def to(to_currency)
    driver = SOAP::WSDLDriverFactory.new(WSDL_URL).create_rpc_driver
    params = {'FromCurrency' => self.code, 
              'ToCurrency' => to_currency.code}
    amount.to_f *  driver.ConversionRate(params).
                       conversionRateResult.to_f
  end
end
  • 获取用户所在国家的货币 :使用Hostip.info对用户的IP地址进行地理编码。
    1. currency.rb 文件中添加Hostip.info的URL常量:
IP_GEOCODE_URL = "http://api.hostip.info/get_xml.php?position=true&ip="
2. 添加新的类方法:
def Currency.get_from_ip(ipaddr)
    results = ''
    open(IP_GEOCODE_URL + ipaddr) { |s| results = XmlSimple::xml_in(s.read, 'force_array' => false) }
    country = results['featureMember']['Hostip']['countryName']
    Currency.find(:first, :conditions => ['country = ?', 
       country.upcase])
end
  • 获取地点使用的货币 :在 location.rb 文件的构造函数末尾添加以下代码:
def initialize(location='Singapore')
    hash = {:appid => YAHOO_APP_ID, :location => location }
    parameters = URI.escape(hash.to_a.collect {|pair| pair.join('=')}.
                 join('&'))
    results = ''
    open(YAHOO_GEOCODE_URL + '?' + parameters) { |s| results = 
         XmlSimple::xml_in(s.read, 'force_array' => false)['Result'] }
    if results.class == Array then
      cities = '<ol>'
      results.each {|res|
        if res['Country'] == 'US' or res['Country'] == 'CA' 
          cities += "<li><a href='/trip/map?location=#{res['City']}, 
                  #{res['State']}, #{res['Country']}'>#{res['City']}, 
                  #{res['State']}, #{res['Country']}</a></li>"
        else
          cities += "<li><a href='/trip/map?location=#{res['City']}, 
                  #{res['Country']}'>#{res['City']}, 
                  #{res['Country']}</a></li>"
        end
      }
      cities += '</ol>'
      raise "More than one city with the same name found! Please 
            choose one from below:" + cities
    end
    @country_code = results['Country']
    @state_code = results['State']
    @lat = results['Latitude'].to_f
    @long = results['Longitude'].to_f  
    hash = {:q => location, :maxRows => 1, :style => 'FULL' }
    parameters = URI.escape(hash.to_a.collect {|pair| pair.join('=')}.
                 join('&'))
    open(GEONAMES_SEARCH_URL + '?' + parameters) { |s| results = 
        XmlSimple::xml_in(s.read, 'force_array' => false)['geoname'] }
    raise "Cannot find this city, please try again with a different 
        state or country." if results == nil
    @city = results['name'] 
    @country = results['countryName']
    @timezone = results['timezone']['content']
    if @country_code == 'US' or @country_code == 'CA'
      @location = "#{@city}, #{@state_code}, #{@country}"
    else
      @location = "#{@city}, #{@country}"
    end
@currency = Currency.find_by_country(@country.upcase)
end
  • 在控制器和视图中显示货币兑换信息
    1. trip_controller.rb 文件中添加 currency 方法:
def currency
    @loc_currency = session[:location].currency
    begin
      @my_currency = Currency.get_from_ip(request.remote_ip)
    rescue
      @my_currency = nil
    end
  end
2. 在`RAILS_ROOT/views/trip`文件夹中创建`currency.rhtml`文件:
<% if @my_currency.nil? then %>
<h2>Local currency</h2>
<p>
Currency conversion is not available because we cannot geocode your 
current location.
</p>
<p>
The local currency is <%= @loc_currency.name%> (<%= @loc_currency.
code%>)
</p>
<% else %>
<h2>Current exchange rate</h2>
<p>
<% @my_currency.amount = 100%>
<%= number_to_currency(@my_currency.amount, :unit => '') %> <%= @
  my_currency.name%> = <%= number_to_currency(@my_currency.to(@loc_  
  currency), :unit => '')%> <%= @loc_currency.name%>
</p>
<h2>Conversion</h2>
<p>Enter an amount and click on 'convert'.</p>
<p>
<% form_remote_tag (:url => {:action => 'convert'}, :update => 
   'converted_to') do %>

<%= hidden_field_tag 'from_currency', @my_currency.code %>

<%= hidden_field_tag 'to_currency', @loc_currency.code %>

<%= text_field_tag 'amount', '100', :size => 5%> <%= @my_currency.
    name%> = <span id='converted_to'>? </span><%= @loc_currency.name%> 
<%= submit_tag 'convert'%>
<% end %>
</p>
<p>
<% form_remote_tag (:url => {:action => 'convert'}, :update => 
   'converted_from') do %>

<%= hidden_field_tag 'to_currency', @my_currency.code %>

<%= hidden_field_tag 'from_currency', @loc_currency.code %>

<%= text_field_tag 'amount', '100', :size => 5%> <%= @loc_
     currency.name%> = <span id='converted_from'>? </span><%= @my_
     currency.name%>  <%= submit_tag 'convert'%>
<% end %>
</p>
<% end%>
3. 在`trip_controller.rb`文件中创建`convert`方法:
def convert
    to_currency = Currency.get(params[:to_currency])
    from_currency = Currency.get(params[:from_currency])
    from_currency.amount = params[:amount]
    @converted_amount = from_currency.to(to_currency)
end
4. 在`RAILS_ROOT/app/views/trip`文件夹中创建`convert.rhtml`模板:
<%= number_to_currency(@converted_amount, :unit => '') %>
2. 显示远程地点与本地时间对比

最后一个标签显示用户的当前本地时间以及远程地点的当前本地时间。
- 安装TZInfo包

$gem install tzinfo
  • 修改 location.rb 文件
    1. 在文件顶部添加:
require 'tzinfo'
2. 添加新的类方法:
def Location.get_from_ip(ipaddr)
    results = ''
    open(IP_GEOCODE_URL + ipaddr) { |s| results = XmlSimple::xml_in(s.read, 'force_array' => false) }
    country = results['featureMember']['Hostip']['countryName']
    Location.new(country)
  end
  • 在控制器中添加 time 方法 :在 trip_controller.rb 文件中添加:
def time
    tz = TZInfo::Timezone.get(session[:location].timezone)
    @time = tz.now
    @own_loc = Location.get_from_ip(request.remote_ip)
    @own_time = TZInfo::Timezone.get(@own_loc.timezone).now
  end
  • 创建视图模板 :在 RAILS_ROOT/app/views/trip 文件夹中创建 time.rhtml 文件:
<h2><%= @own_loc.location%></h2>
Timezone: <%= @own_loc.timezone %>
<div class="time"><%= @own_time.strftime "%I:%M %p " %></div>
<h2><%= session[:location].location%></h2>
Timezone : <%= session[:location].timezone%><br/>
<div class="time"><%= @time.strftime "%I:%M %p" %></div>
3. 异常处理

由于应用高度依赖互联网、外部访问速度和远程API的可用性,可能会出现异常和错误。我们可以通过以下方式进行异常处理:
- 在 trip_controller.rb 文件中重写 rescue_action_in_public 方法:

def rescue_action_in_public(exception)
    render :template => 'error'
end
  • RAILS_ROOT/app/views 文件夹中创建 error.rhtml 文件:
<h1>Service not available at the moment</h1>
<p>
Something's not happening right, probably not getting data from the 
remote service. Try again!  
</p>
  • trip_controller.rb 文件中添加 local_request? 方法:
def local_request?
    false
end
  • 在环境文件( development.rb test.rb )中修改参数:
config.action_controller.consider_all_requests_local = false
4. 总结

通过上述步骤,我们实现了旅游应用中的货币兑换和时间显示功能,并对可能出现的异常进行了处理。整个过程涉及到多个API的调用和数据库操作,确保了应用的功能完整性和稳定性。

以下是货币兑换功能的流程图:

graph TD;
    A[获取货币代码数据] --> B[创建数据库迁移文件];
    B --> C[创建Currency类];
    C --> D[填充数据到数据库];
    D --> E[完善Currency类];
    E --> F[获取用户所在国家的货币];
    F --> G[获取地点使用的货币];
    G --> H[在控制器和视图中显示货币兑换信息];

以下是时间显示功能的流程图:

graph TD;
    A[安装TZInfo包] --> B[修改location.rb文件];
    B --> C[在控制器中添加time方法];
    C --> D[创建视图模板];

通过这些功能的实现,用户可以在旅游应用中方便地了解货币兑换信息和不同地点的时间差异。

旅游应用中的货币兑换与时间显示功能实现

5. 货币兑换功能总结

货币兑换功能的实现是一个较为复杂的过程,涉及到数据的获取、数据库的操作以及与外部服务的交互。下面对货币兑换功能的关键步骤进行总结:
|步骤|操作|
| ---- | ---- |
|获取货币代码数据|从ISO网站获取货币代码列表,保存为CSV文件|
|创建数据库迁移文件|生成并编辑迁移文件,创建 currencies 表|
|创建Currency类|在 models 文件夹中创建 currency.rb 文件|
|填充数据到数据库|生成迁移文件,将CSV文件中的数据插入数据库|
|完善Currency类|在 currency.rb 文件中添加货币转换方法|
|获取用户所在国家的货币|使用Hostip.info对用户IP进行地理编码,获取对应货币|
|获取地点使用的货币|在 location.rb 文件中添加代码,获取地点货币|
|在控制器和视图中显示货币兑换信息|在 trip_controller.rb 中添加方法,在视图中创建模板显示信息|

6. 时间显示功能总结

时间显示功能主要依赖于TZInfo包和Hostip.info服务,通过获取用户和远程地点的时区信息,显示对应的时间。以下是时间显示功能的关键步骤总结:
|步骤|操作|
| ---- | ---- |
|安装TZInfo包|使用 gem install tzinfo 命令安装|
|修改 location.rb 文件|添加 tzinfo 依赖,添加 get_from_ip 方法|
|在控制器中添加 time 方法|在 trip_controller.rb 中添加 time 方法,获取用户和远程地点的时间|
|创建视图模板|在 views/trip 文件夹中创建 time.rhtml 文件,显示时间信息|

7. 异常处理总结

由于应用依赖外部服务,异常处理是必不可少的。通过重写 rescue_action_in_public 方法和创建错误模板,我们可以在出现异常时向用户显示友好的错误信息。异常处理的关键步骤如下:
|步骤|操作|
| ---- | ---- |
|重写 rescue_action_in_public 方法|在 trip_controller.rb 中重写该方法,渲染错误模板|
|创建 error.rhtml 文件|在 views 文件夹中创建 error.rhtml 文件,显示错误信息|
|添加 local_request? 方法|在 trip_controller.rb 中添加该方法,使所有请求视为非本地请求|
|修改环境文件参数|在 development.rb test.rb 中修改参数,显示错误页面|

8. 整体功能评估

通过实现货币兑换和时间显示功能,我们的旅游应用为用户提供了更丰富的信息。货币兑换功能让用户可以方便地了解不同货币之间的汇率,时间显示功能则帮助用户掌握不同地点的时间差异。然而,这些功能也存在一些潜在的问题:
- 依赖外部服务 :应用高度依赖Hostip.info、WebserviceX等外部服务,这些服务的可用性和稳定性会影响应用的正常运行。
- 网络问题 :由于需要与外部服务进行交互,网络状况不佳可能导致数据获取失败或延迟。
- 异常处理的局限性 :虽然我们进行了异常处理,但对于一些复杂的异常情况,可能无法提供足够详细的错误信息。

9. 未来优化方向

为了提高应用的性能和稳定性,我们可以考虑以下优化方向:
- 缓存机制 :对于一些不经常变化的数据,如货币代码列表,可以使用缓存机制减少对外部服务的请求。
- 多服务备份 :为了避免单一服务故障导致应用无法正常运行,可以考虑使用多个服务进行备份。
- 更详细的异常处理 :对不同类型的异常进行分类处理,提供更详细的错误信息给用户。

10. 总结

通过一系列的操作,我们成功实现了旅游应用中的货币兑换和时间显示功能,并对可能出现的异常进行了处理。整个过程涉及到多个API的调用、数据库操作以及异常处理,确保了应用的功能完整性和稳定性。以下是整体功能实现的流程图:

graph TD;
    A[货币兑换功能] --> B[时间显示功能];
    A --> C[异常处理];
    B --> C;
    C --> D[整体功能完成];

通过这些功能的实现,用户可以在旅游应用中方便地了解货币兑换信息和不同地点的时间差异。同时,我们也对应用的潜在问题进行了分析,并提出了未来的优化方向,以进一步提升应用的性能和用户体验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值