rails

2024-10-11

rails(精选6篇)

rails 篇1

VMware EVO家族作为革新的超融合基础架构目前主要有两款产品, 分别主要面向中型以上的企业和大型数据中心用户。其中, VMware EVO:RAIL是EVO家族的首款解决方案, 将会在2014下半年由合作伙伴负责发售;而VMware EVO:RACK现在还只有预览版。

VMware EVO:RAIL作为云计算构建组元, 以超融合架构形态, 让服务供应商、IT集成商可以通过提供一揽子云计算方案, 简化云部署和云架构的管理运维。EVO:RAIL中包括了:v Sphere Enterprise Plus、v Center Server、VMware Virtual SAN、v Center Log Insight以及专门开发的EVO:RAIL引擎, 这些软件将均与合作伙伴的硬件进行集成。VMware EVO:RAIL引擎是VMware专门开发的管理软件, 它将简化设备部署、配置以及管理, 不仅能够自动化管理GUI, 还能够实现软件自动升级。EVO:RAIL是一个可线性升级扩展的软件定义数据中心的基础架构 (SDDC) , 提供了计算、网络、存储与管理一体化软件, 最大限度优化私有/混合云以及用户的计算能力。同时, 高弹性设计保证了应用不会由于维护或者硬盘、网络、主机错误而下线。此外, VMware EVO:RAIL简化的基础架构设计方式提供了流线型的采购及部署方式, 降低了IT总拥有成本, 能够满足用户未来不断增长的需求。

目前VMware EVO主要是针对中端市场, 适合于差不多约100台通用虚拟机的市场。在工作负载上, EVO主要是为了通用的工作负载而设计, 同时, 也支撑虚拟桌面基础架构 (VDI) 以及远程办公室等应用环境。

VMware EVO主要实现的目的是, 能够为系统集成商和传统IT架构的技术提供商, 快速地提供端对端的整体云计算打包方案。相对于欧美市场, 中国的厂商和集成商对于以工作负载为核心的智能管理以及整合部署的经验非常有限。在云计算部署的过程中, VM-ware EVO:RAIL通过提供端对端的整合和以VMware为核心的售后服务, 最大限度地降低厂商、集成商和运营商的风险系数。

VMware将会与戴尔、EMC、富士通、浪潮、Net One和超微合作, 携手为用户提供超融合基础架构以及部署管理的解决方案。在IT演进的过程中, 从IT架构部署到云计算IT服务交付演进过程, 给传统IT厂商的利润空间带来了很大的挤压。VMware EVO作为云计算使能技术平台, 为VMware的战略合作伙伴提供了相当大的技术发展空间和利润增长空间。目前, 在中国市场上, 虽然最终用户在云计算上投资增长很快, 但是, 多数厂商和集成商的云计算部署管理经验有限。VMware EVO可以最大程度简化云计算部署管理复杂性, 提高云服务管理效率。同时, VMware通过一站式服务, 进一步助力在各国家和地区战略合作伙伴的资源整合效率, 为用户提供了以云服务形式交付的最佳硬件/软件方案组合, 创造了双赢的局面。

VMware EVO:RAIL提高浪潮云计算市场竞争力

中桥调研显示, 中国市场对私有云和混合云的市场接受力度正在快速增加, 而公有云的接受力度则较低。中国用户开始意识到IT演进是一个持续的过程, 如何保证应用和负载可以跨现有数据中心和云计算实现无缝迁移, 高度融合, 决定着云计算投资回报率。

目前, 浪潮是首批VMware EVO:RAIL合作伙伴中唯一的中国IT厂商。VMware EVO与浪潮技术高度整合, 可以为中端市场用户提供一揽子云计算方案。浪潮可以借助于VMware的EVO快速为中国用户提供混合云技术平台;与此同时, 通过与Open Stack技术整合, 保证了IT演进过程中技术的灵活性。在中国云计算演进过程中, 这种合作将快速提升浪潮的方案整合能力和效率, 降低云计算技术开发周期和投入。

云计算和T3平台正在快速改变着行业格局、传统业务模式以及ICT市场格局。中桥认为, 浪潮与VMware EVO:RAIL的紧密合作, 让浪潮可以快速针对各行业集成商提供端到端的云计算一揽子架构方案, 通过为云计算产业链优质集成商提供优质 (可靠、高利润空间、灵活、简单) 服务, 提升自身在中国云计算市场上的优质资源 (客户、渠道、利润) 持有率。浪潮与VM-ware这种合作方式, 既提高了双方在云计算演进过程中的执行能力和利润空间;同时, 也提升了整个VMware在与国内厂商合作过程中的战略价值, 以及VMware做为中国IT厂商云计算技术使能伙伴的地位。

rails 篇2

这篇文章主要介绍了在Ruby on Rails中进行高效的单元测试的教程,使用到了Ruby的RSpec和Factory Girl框架,需要的朋友可以参考下

在笔者开发的系统中,有大量的数据需要分析,不仅要求数据分析准确,而且对速度也有一定的要求的,没有写测试代码之前,笔者用几个很大的方法来实现这种需求。结果可想而知,代码繁杂,维护困难,难于扩展。借业务调整的机会,笔者痛定思痛,决定从测试代码做起,并随着不断地学习和应用,慢慢体会到测试代码的好处。

改变思路:能做到从需求到代码的过程转换,逐步细化;

简化代码:力图让每个方法都很小,只专注一件事;

优化代码:当测试代码写不出来,或者需要写很长的时候,说明代码是有问题的,是可以被分解的,需要进一步优化;

便于扩展:当扩展新业务或修改旧业务时,如果测试代码没有成功,则说明扩展和修改不成功;

时半功倍:貌似写测试代码很费时,实际在测试、部署和后续扩展中,测试代码将节省更多的时间。

环境搭建

笔者采用的测试环境是比较流行通用的框架:RSpec + Factory Girl,并用autotest自动工具。RSpec是一种描述性语言,通过可行的例子描述系统行为,非常容易上手,测试用例非常容易理解。Factory Girl可以很好的帮助构造测试数据,免去了自己写fixture的烦恼。Autotest能自动运行测试代码,随时检测测试代码的结果,并且有很多的插件支持,可以让测试结果显示的很炫。

第一步 安装rspec和rspec-rails

在命令行中执行如下命令:

$ sudo gem install rspec v = 1.3.0$ sudo gem install rspec-rails v = 1.3.2

安装完成后,进入rails应用所在的目录,运行如下脚本,生成spec测试框架:

$ script/generate rspec exists lib/tasks identical lib/tasks/rspec.rake identical script/autospec identical script/spec exists spec identical spec/rcov.opts identical spec/spec.opts identical spec/spec_helper.rb

第二步 安装factory-girl

在命令行中执行如下命令:

$ sudo gem install rspec v = 1.3.0$ sudo gem install rspec-rails v = 1.3.2

安装完成后,进入rails应用所在的目录,运行如下脚本,生成spec测试框架:

$ script/generate rspec exists lib/tasks identical lib/tasks/rspec.rake identical script/autospec identical script/spec exists spec identical spec/rcov.opts identical spec/spec.opts identical spec/spec_helper.rb

第二步 安装factory-girl

在命令行中执行如下命令:

$ sudo gem install factory-girl

在config/environment/test.rb中,加入factory-girl这个gem:

config.gem “factory_girl”

在spec/目录下,增加一个factories.rb的文件,用于所有预先定义的model工厂。

第三步 安装autotest

在命令行中执行如下命令:

$ sudo gem install ZenTest$ sudo gem install autotest-rails

然后设置与RSpec的集成,在rails应用的目录下,运行如下的命令,就可以显示测试用例的运行结果。

RSPEC=true autotest or autospec

在自己的home目录下,增加一个.autotest设置所有的Rails应用的autotest插件。当然,也可以把这个文件加到每个应用的根目录下,这个文件将覆盖home目录下的文件设置。autotest的插件很多,笔者用到如下的plugin:

$ sudo gem install autotest-growl$ sudo gem install autotest-fsevent$ sudo gem install redgreen

设置.autotest文件,在.autotest中,加入如下代码。

require ‘autotest/growl‘ require ‘autotest/fsevent‘ require ‘redgreen/autotest‘ Autotest.add_hook :initialize do |autotest| %w{.git .svn .hg .DS_Store ._* vendor tmp log doc}.each do |exception| autotest.add_exception(exception) endend

测试经验

安装了必要的程序库以后,就可以写测试代码了。本例中,所有应用都是在Rails 2.3.4上开发的,RSpec采用的是1.3.0的版本。为了很好的说明问题,我们假定这样的需求:判断一个用户在一个时间段内是否迟到。写测试代码时都是遵循一个原则,只关心输入和输出,具体的实现并不在测试代码的考虑范围之内,是行为驱动开发。根据这个需求,我们将会设计方法absence_at(start_time,end_time),有两个输入值start_time和end_time以及一个输出值,类型是boolean。对应的测试代码如下:

describe “User absence or not during [start_time,end_time]” do before :each do @user = Factory(:user) end it “should return false when user not absence ” do start_time = Time.utc(,11,9,12,0,0,0) end_time = Time.utc(2010,11,9,12,30,0) @user.absence_at(start_time,end_time).should be_false end it “should return true when user absence ” do start_time = Time.utc(2010,11,9,13,0,0,0) end_time = Time.utc(2010,11,9,13,30,0) @user.absence_at(start_time,end_time).should be_ture endend

测试代码已经完成。至于absence_at方法我们并不关心它的实现,只要这个方法的结果能让测试代码运行结果正确就可以。在此测试代码的基础上,就可以大胆地去完成代码,并根据测试代码的结果不断修改代码直到所有测试用例通过。

Stub的使用

写测试代码,最好首先从model开始。因为model的方法能很好与输入输出的原则吻合,容易上手。最初的时候,你会发现mock和stub很好用,任何的对象都可以mock,并且在它的基础上可以stub一些方法,省去构造数据的麻烦,一度让笔者觉得测试代码是如此美丽,一步步的深入,才发现自己陷入了stub的误区。还是引用上面的例子,我们的代码实现如下:

class User < ActiveRecord::Base def absence_at(start_time,end_time) return false if have_connection_or_review?(start_time,end_time) return (login_absence_at?(start_time,end_time) ? true : false) endend

按照最初写测试代码的思路,本方法中存在三种情况,即需要三个用例,而且还调用了其他两个方法,需要对他们进行stub,于是就有了下面的测试代码。记得当时完成后还很兴奋,心中还想:这么写测试代码真有趣。

before(:each) do @user = User.newenddescribe “method ” do s = Time.now e = s + 30.minutes # example one it “should be false when user have interaction or review” do @user.stub!(:have_connection_or_review?).with(s,e).and_return(true) @user.absence_at(s,e).should be_false end # example two it “should be true when user has no interaction and he no waiting at platform” do @user.stub!(:have_connection_or_review?).with(s,e).and_return(false) @user.stub!(:login_absence_at?).with(s,e).and_return(true) @user.absence_at(s,e).should be_true end # example three it “should be false when user has no interaction and he waiting at platform” do @user.stub!(:have_connection_or_review?).with(s,e).and_return(false) @user.stub!(:login_absence_at?).with(s,e).and_return(false) @user.absence_at(s,e).should be_false end end

上面的测试代码,是典型把代码的实现细节带到了测试代码中,完全是本末倒置的。当然这个测试代码运行的时候,结果都是正确的。那是因为用stub来假定所有的子方法都是对的,但是如果这个子方法have_connection_or_review?发生变化,它不返回boolean值,那么将会发生什么呢?这个测试代码依然正确,可怕吧!这都没有起到测试代码的作用。

另外,如果是这样,我们不仅要修改have_connection_or_review?的测试代码,而且还要修改absence_at的测试代码。这不是在增大代码维护量吗?

相比而言,不用stub的测试代码,不用修改,如果Factory的数据没有发生变化,那么测试代码的结果将是错误的,因为have_connection_or_review?没有通过测试,导致absence_at方法无法正常运行。

其实stub主要是mock一些本方法或者本应用中无法得到的对象,比如在tech_finish?方法中,调用了一个file_service来获得Record对象的所有文件,在本方法测试代码运行过程中,无法得到这个service,这时stub就起作用了:

class A < ActiveRecord::Base has_many :records def tech_finish? self.records.each do |v_a| return true if v_a.files.size == 5 end return false endendclass Record < ActiveRecord::Base belongs_to :a has_files # here is a service in gemend

所对应的测试代码如下:

describe “tech_finish?” do it “should return true when A‘s records have five files” do record = Factory(:record) app = Factory(:a,:records=>[record]) record.stub!(:files).and_return([1,2,3,4,5]) app.tech_finish?.should == true end it “should return false when A‘s records have less five files” do record = Factory(:record) app = Factory(:a,:records=>[record]) record.stub!(:files).and_return([1,2,3,5]) app.tech_finish?.should == false endend

Factory的使用

有了这个工厂,可以很方便的构造不同的模拟数据来运行测试代码,

还是上面的例子,如果要测试absence_at方法,涉及到多个model:

HistoryRecord:User的上课记录

Calendar:User的课程表

Logging:User的日志信息

如果不用factory-girl构造测试数据,我们将不得不在fixture构造这些测试数据。在fixture构造的数据无法指定是那个测试用例使用,但是如果用Factory的话,可以为这个方法专门指定一组测试数据。

Factory.define :user_absence_example,:class => User do |user| user.login “test” class << user def default_history_records [Factory.build(:history_record,:started_at=>Time.now), Factory.build(:history_record,:started_at=>Time.now)] end def default_calendars [Factory.build(:calendar), Factory.build(:calendar)] end def default_loggings [Factory.build(:logging,:started_at=>1.days.ago), Factory.build(:logging,:started_at=>1.days.ago)] end end user.history_records {default_history_records} user.calendars {default_calendars} user.loggings {default_loggings}end

这个测试数据的构造工厂,可以放在factories.rb文件中,方便其他测试用例使用,也可以直接放到测试文件的before中,仅供本测试文件使用。通过factory的构造,不仅可以为多个测试用例共享同一组测试数据,而且测试代码也简洁明了。

before :each do @user = Factory.create(:user_absence_example)end

Readonly的测试

在笔者的系统中,大量使用了acts_as_readonly,从另外一个数据库来读取数据。由于这些model并不在本系统中,所以当用Factory构造测试数据的时候,总会有问题。虽然也可以使用mock来达到这个目的,但是由于mock的局限性,还是无法灵活的满足构造测试数据的需要。为此,扩展了一些代码,使得这些model依然可以测试。核心思想则是,根据配置文件的设置,将对应的readonly的表创建在测试数据库,这个操作在运行测试之前执行,这样就达到与其他model一样的效果。site_config配置文件中,关于readonly的配置格式如下:

readonly_for_test: logings: datetime: created_at string: status integer: trainer_id

Gem的测试

Gem在Rails中被广泛使用,而且是最基础的东西,因此它的准确无误就显得更加重要。在不断实践的基础上,笔者所在的团队总结出一种用spec测试gem的方法。假设我们要测试的gem是platform_base,步骤如下:

1. 在gem的根目录下创建一个目录spec(路径为platform_base/spec)。

2. 在gem的根目录下创建文件Rakefile(路径为platform_base/Rakefile),内容如下:

require ‘rubygems‘require ‘rake‘require ‘spec/rake/spectask‘Spec::Rake::SpecTask.new(‘spec‘) do |t| t.spec_opts = [‘--options‘, “spec/spec.opts”] t.spec_files = FileList[‘spec/**/*_spec.rb‘]end

3. 文件在spec目录下创建spec.opts(路径为platform_base/spec/spec.opts),内容如下:

代码如下:

--colour

--format progress

--loadby mtime

--reverse

4. 在spec目录下,创建一个Rails app,名为test_app。这个新应用需要有spec目录和spec_helper.rb文件。

5. 为了保持简化,把这个新app(test_app)整理一下,删除vendor和public目录,最终的结构如下:

代码如下:

test_app

|- app

|- config

|  |- environments

|  |- initializers

|  |- app_config.yml

|  |- boot.rb

|  |- database.yml

|  |- environment.rb

|  - routes.rb

|- db

|  - test.sqlite3

|- log

- spec

- spec_helper.rb

6. 在config/environment.rb配置文件中,增加如下代码:

Rails::Initializer.run do |config| config.gem ‘rails_platform_base‘end

7. 在platform_base/spec/目录下增加helpers_spec.rb文件,内容如下:

require File.join(File.dirname(__FILE__), ‘test_app/spec/spec_helper‘)

describe “helpers” do describe “url_of” do before do Rails.stub!(:env).and_return(“development”) @controller = ActionController::Base.new end it “should get url from app‘s configration” do @controller.url_of(:article, :comments, :article_id => 1).should == “www.idapted.com/article/articles/1/comments” @controller.url_of(:article, :comments, :article_id => 1, :params=>{:category=>“good”}).should == “www.idapted.com/article/articles/1/comments?category=good” end endend

至此,准备工作已经就绪,可以在platform_base目录下,运行rake spec来进行测试,当然现在什么都不会发生,因为还没有测试代码呢。本方法中,最关键的就是下面的require语句,不仅加载了Rails environment,而且把gem在test_app中使用并测试。

require File.join(File.dirname(__FILE__), ‘test_app/spec/spec_helper‘)

Controller的测试

对于controller的测试,一般来说比较简单,基本是三段式:初始化参数、请求方法、返回render或者redirect_to。如下例中,对某个controller的index方法的测试:

describe “index action” do it “should render report page with the current month report” do controller.stub!(:current_user).and_return(@user) get :index,{:flag => “test”} response.should render_template(“index”) endend

有些controller会设置session或者flash,这时的测试代码就一定要检查这个值设置的是否正确,而且还需要增加测试用例来覆盖不同的值,这样才能对方法进行全面的测试。如下例:

describe “create action” do it “should donot create new user with wrong params” do post :create response.should redirect_to(users_path) flash[:notice].should == “Create Fail!” end it “should create a new user with right params” do post :create, {:email => “abc@eleutian.com”} response.should redirect_to(users_path) flash[:notice].should == “Create Successful!” endend

同时,也需要对controller的assigns进行测试,以保证返回正确的数据。如下例:

before(:each) do @course = Factory(:course)end describe “show action” do it “should render show page when flag != assess and success” do get :show, :id => @course.id, :flag =>“test” response.should render_template(“show”) assigns[:test_paper].should == @course assigns[:flag].should == “test” end it “should render show page when flag == assess and success” do get :show, :id => @course.id, :flag =>“assess” response.should render_template(“show”) assigns[:test_paper].should == @course assigns[:flag].should == “assess” end end

View的测试

View的测试代码写的比较少,基本上是把核心的view部分集成到controller中来测试。主要用integrate_views方法。如下例:

describe AccountsController do integrate_views describe “index action” do it “should render index.rhtml” do get :index response.should render_template(“index”) response.should have_tag(“a[href=?]”,new_account_path) response.should have_tag(“a[href=?]”,new_session_path) end endend

总结展望

在写测试代码的时候,并不一定要事无巨细,有些比较简单的方法以及Rails的内部的方法,如named_scope,就完全没有必要测试。本文中,只介绍了用rspec写单元测试的代码,对于集成测试没有涉及,这也是今后努力的一个方向。

rails 篇3

Moreover, its role of being “originally made in Germany” now is being questioned as it might be“made in China”.

Actually, the People’s Daily reported the Halfen event early in December 2011. But the following report was nowhere to be seen. Why did Halfen, a well-established German company famous for its preciseness, resort to deception in China? Then, how can an enterprise which never sent out its products for examination or brought forth relevant examination reports nearly take the dominant place in the market?

A source explained that the Halfen in China is not the German Halfen as its headquarters in Germany knows nothing about this. In addition, Halfen China is famous for its PR capability and there supplies 70% of the cast-in channels in China.

The Ministry of Railway is reported to attach great importance to this matter and the investigation has already begun.

Century-old Halfen Might Be “Pirated”

Halfen is an old brand which is widely respected and praised in the world. This company was founded in 1929 and enjoys unprecedented fame in the global construction area. The cast-in channels it produces is the most popular among all similar products and are widely used in the high-speed railways of Germany, Japan and France.

Halfen stepped into China in 2005. In that year, China 4th Railway Survey and Design Group Co., Ltd introduced Halfen’s cast-in channels in the Wuhan-Guangzhou High-speed Railway. In the same year, Hong Kong Goldway Co., Ltd, Halfen’s agent in Asia, appointed Beijing Anke Fortune Construction Management Co., Ltd as the sales agent of Halfen’s products in mainland China. As the market keeps growing, Halfen acquired its Hong Kong agent and founded the Halfen Beijing Company in China.

According to the report from the People’s Daily, some netizens revealed that the Halfen cast-in channels imported from Germany that were applied in the high-speed rails between Shanghai and Kunming, and between Hefei and Fuzhou, were actually made in China. The samples taken from the construction site were sent for the examination and their fatigue- and fire-resistant performance could not meet the standard of the Design Institute of the Ministry of Railway.

In addition, the People’s Daily also reported that subordinate processing plants of Halfen Beijing China could be seen in Yizhuang and Sanhe – both are counties under the administration of Beijing. The operators of these plants were said to have admitted that they manufactured cast-in channels labeled as originally made in Germany. An insider familiar with the supply chain of cast-in channels said that 70% of the Halfen castin channels in China were made in China and only one quarter was imported from Germany. There is a huge disparity in quality between the original products and the ones made in China.

In November 2010, Hao Jiwei, vice general manager of Halfen Beijing Company, said that the Wuhan-Guangzhou Railway, Zhengzhou-Xi’an Railway, Guangzhou-Shenzhen Railway, Hefei-Fuzhou Railway, Beijing-Shanghai Railway and other railways – 20 in total – used the products of Halfen. Based on this, Halfen, or fake Halfen, indeed takes 70% of the Chinese market.

Then why did such a well-established enterprise risk its own fame to substitute low-quality products for high-quality ones? A source close to the Ministry of Railway said: “Halfen’s headquarters in Germany might not know about this thing. Its operating pattern is featured with sales agents responsible for taking orders while headquarters for producing and sending products. If the agent company in China produced the products by themselves, Halfen Germany might not be aware of this matter.” He said that most of the Halfen products in China are“pirated”, or, commonly called “Shanzhai” products in China.

Journalists used “Halfen cast-in channels” as the key in Baidu and find tens of thousands of links that claimed to be the agent of Halfen cast-in channels. Journalists called one of them randomly and were told that “the Halfen label is used but the products are not made in Germany”. Actually, Halfen allows no companies to produce cast-in channels in China.

An anonymous insider from the Ministry of Railway said that most of the said imported Halfen cast-in channels from Germany were actually made in China. Their price is very low and in order to lower the cost, many manufacturers in China use inferior materials and downgrade the quality standard.

“The Amazing Halfen PR Department”

The bidding documents of the basic construction materials for railways have definite stipulations: suppliers of cast-in channels and related products must have six examination reports about size, dynamic performance, fatigue resistance, corruption prevention, current-carrying performance and fire resistance before they make official bidding offers. However, Halfen China never submitted the six reports in China; instead, it used the corporate standard in the German civil construction to replace the examination reports.

The report about the quality of Halfen cast-in channels in China was first seen in December 2011 but no sequels were found. What made even the People’s Daily, one of the largest newspaper in China shut up? Why could the supplier win the bidding without offering documents as required? Why was Halfen still so popular when the Ministry of Railway was short of capital? The answers to these questions all refer to the “amazing PR department of Halfen”.

The aforementioned report from the People’s Daily quoted that all the design plans for the Changsha-Yuping line in the Shanghai-Kunming Railway made by the China 3rd Railway Survey and Design Institute contained the technological requirements about cast-in channels in accordance with the technological data provided by Halfen. Simply speaking, the cast-in channels for this project were tailor-made by Halfen before the start of project. Meanwhile, the designer required the constructor to purchase those products in advance since “there were no similar products available in China”.

The Ministry of Railway published the Implementation Rules about the Accreditation of Manufacturers of Important Overhead Lines for Railways in 2007. According to this document, relevant manufacturers need to go through the examination and accreditation by the Ministry of Railway before launching their products in the market.

When Halfen entered China in 2005, such a rule did not come out. The only standard that could be followed in construction is issued by the China Railway Design Institution. But even after the issuance of the rule, Halfen still followed the standard made by the China Railway Design Institution.

After 2010, the Ministry of Railway made several adjustments to the purchasing system of basic construction materials for railways and set up strict examination rules for the purchased materials. But every time Halfen could miraculously remained uninfluenced and win the bidding. In comparison, some domestic suppliers, who claimed to be able to produce cast-in channels with the same quality, never got the same opportunities.

What’s more admired by its peers is that Halfen could always get money from the Ministry of Railway even though its products are 30% more expensive than similar products made by domestic companies. The price never went down with the industrial depression; instead, it went up at times.

rails 篇4

1 Ruby on Rails技术介绍

1.1 Rails框架概述

Ruby on Rails,也简称RoR或Rails,是一个使用Ruby语言写的开源网络应用框架,它是严格按照MVC结构开发的。它努力使自身保持简单,来使实际的应用开发时的代码更少,使用最少的配置。

Rails的设计原则包括“不要重复自己”(Don't Repeat Yourself)和“约定胜于配置”(Convention Over Configuration)[4]。Rails应用框架如图1所示。

1.2 Rails中的MVC模式

模型(Model):负责维持应用程序的状态,有时这种状态是短暂的,只在用户的几次操作之间存在;有时则是持久的,需要将其保存在应用程序之外(通常是数据库中)。模型携带着数据,但又不只是数据;它还负责执行施加于这些数据之上的业务规则。因此模型不仅是数据的容器,还是数据的监护者。

视图(View):负责生成与用户进行交互的界面,通常会根据模型中的数据来生成。对于老式的应用程序来说,视图就是由HTML元素组成的界面,在新应用程序中,HTML依然在视图中扮演着重要的角色,但是一些新技术已经层出不穷,例如在本文所介绍的项目中使用到的RHTML便是其中一种,另外HAML也是最近兴起的一门视图表达技术。视图可以允许用户以多种方式输入数据,但输入的数据是一定不会由视图本身来处理的,视图的唯一工作就是显示数据。当然出于不同的目的,可能会有多个视图访问同一个模型。

控制器(Colltr0ller):负责协调整个应用程序的运转,接收用户的输入,并调用模型和视图去完成用户的需要。当请求到达时,控制器接收请求,并决定由哪个模型构件去处理请求,确定由哪个视图来显示模型处理返回的数据[6]。

在Rails应用程序中,路由组件接收来自浏览器的URL请求,该组件判断应该将请求发送到应用程序的什么部分、如何解析这一请求。这一阶段将找出controller代码中的某个action,要求他来处理请求。Action可以查阅请求中携带的数据,可以与model交互,也可以调用别的action。最后,action会为view准备充分的信息,view则将所需的信息展现给用户。

MVC架构的简单示意图如图2所示。

1.3 Active Record

Active Record是一个可以方便的实现与数据库交互的大型程序库,这种交换被称为对象—关系映射(ORM)。ORM程序库的核心是实现数据库表和类之间的映射,每一行将映射成为类的一个实例,而每一列的值将是该实例的一个属性。

2 系统分析

2.1 开发环境及开发工具

系统运行在Windows环境下,运用Ruby on Rails框架,采用mysql数据库以及apache服务器进行开发。开发工具是In-stantrails2.0+SciTE。

Instant Rails是一个一站式的Rails运行环境,包含Ruby、Rails、Apache和MySQL,所有都已经配置好了能立刻运行。不需要安装,你只要将它放在你喜欢的地方然后运行它就可以了。它不会修改你的系统的环境。

2.2 需求分析

本系统的设计目的在于加强师生间的互动,提高教师的教学质量;同时也可以对期末学生成绩进行客观,合理地评价提供依据。充分利用校园网网路资源,用户只要在校园网中的任意一台机器机器上登录就可以进行学习。因此设计系统时要保证系统更新快捷、维护方便、保证系统安全。为此在设计过程中采用如下原则:

1)灵活性原则:在进行数据库系统设计时,为保证系统灵活的开放性,设计数据表时尽量进行拆分,这样虽然在进行查询时,虽然降低了速度,但保证了需求更改时,减少对上层代码的修改。

2)实用性原则:系统应具有友好的界面,可操作性强,便于维护和管理以提高操作人员的工作效率。

3)安全性原则:对用户权限进行分级密码管理,防止计算机病毒的入侵,防止非法用户入侵系统,对数据库系统中数据进行备份,保证系统能够恢复。

2.3 系统架构

系统的体系结构采用B/S模式,由客户端的表示层、业务逻辑层、数据库层3部分组成,利于系统的开发、维护、部署以及扩展。表示层:负责直接与用户交换,采用div布局并使用css来实现页面的外观,维护方便。业务逻辑层:采用AJAX on Rails实现系统的全部功能。数据库层:采用mysql数据库,负责后台数据的存储。

3 系统功能模块设计与实现

3.1 系统功能模块

如图3所示。

3.2 系统功能模块设计

根据教学需要,系统分成2类用户:学生,教师(管理员),分别给予这2类用户不同权限。

系统由学生子系统,教师子系统组成,包括注册登录,作业提交,上机管理,上机测验,发送邮件,信息查询,作业检测,密码找回。

3.2.1 注册登录

采用ajax无刷新验证登录/注册信息是否合法,若验证全部通过,则提示登录/注册成功并转向系统首页。若验证不通过,则提示不通过的原因并高亮显示。

3.2.2 上机管理

包括上机签到、上机签退,一天只能签到一次。通过签到、签退记录上机情况,统计签到次数,上机时间,实现机房上机管理自动化,同时对于期末学生平时成绩的评定提供量化依据。

3.2.3 发送邮件

学生可以通过系统发送邮件与教师交流,加强师生交互,提高教学质量。

3.2.4 作业提交

布置课后作业,学生完成后通过网络提交,提交的文件格式只能是word或text文本文件并限制文件大小不能超过3M,系统根据学生的注册信息自动生成相应的作业提交目录。网上提交作业方便、灵活,同时对于期末学生平时成绩的评定提供量化依据。

3.2.5 密码找回

对于忘记密码的用户,有2中方式找回密码。

方式1:输入用户名,ajax实现根据用户名在数据库中查询注册时填写的提示信息并显示在页面上,提示用户输入提示信息的答案,点击找回链接。若信息通过数据库验证,则在页面显示密码,否则提示出错信息。

方式2:根据注册时使用的邮箱信息发送邮件通知用户账号,密码信息。因为注册用户时要求相同邮箱不能重复注册,因此可以保证用户、密码的唯一性。

3.2.6 上机测验

要巩固教学效果,留一定的作业是必不可少的教学环节,对于计算机基础及程序设计课程来讲。不但要留作业,还要保证要上机作业实践,通过该功能就能够使学生在上机辅导时进行上机实践,同时对所做的练习进行评分。在没有使用计算机辅助教学系统时,该过程都是由教师人工评阅,教师花费大量的时间但效果并不好,为此该模块通过计算机进行阅卷并统计分数,督促学生上机实践,达到很好的效果,使教师由更多的时间专注于教学。

3.2.7 信息查询

可以根据用户名/课序号两种方式查询信息。以用户名查询时可以显示用户的基本信息并提供修改操作修改基本注册信息(学号不可改),点击详细信息还可以查看学生这个学期的学习情况,包括基本信息,上机情况,作业提交情况及平时测验情况,为教师了解学生学习情况提供依据。对学生普遍掌握较差的知识点可以一目了然,给决策提供依据,同时对于期末学生平时成绩的评定提供量化依据。

3.2.8 作业检查

根据作业检查条件(如作业序号等),利用AJAX查询作业提交情况。利用数据库中保存的学生用户信息,搜索相应作业提交目录下的文件。若目录下不存在相应的作业提交文件,则在页面上显示未交作业的学生的学号,并在后台发送邮件信息提醒学生及时提交作业,避免学生遗忘作业,加强师生交互,提高教学质量。

3.3 系统实现

3.3.1 系统主页

如图4所示。

3.3.2 系统开发的部分代码实现

3.3.2. 1 作业检查的AJAX代码实现

作业检查的功能如3.2.8所示

3.3.2. 2 作业检查结果

如图5所示。

4 遇到的问题及解决思路

4.1 乱码问题及解决思路

遇到的中文处理问题主要有以下3种:

4.1.1 rhtml显示乱码

这个容易解决,只要统一编码,把rhtml,controller.rb,model.rb文件统一成utf-8编码格式。

4.1.2 数据库中的内容在浏览器中显示为乱码,或输入的中文存进数据库变成乱码

这个问题处理起来要复杂一些,和数据库的服务器的字符集设置,还有数据库客户端设置都有关系,与rhtml的编码设置也有关。

1)修改rails默认编码成utf8

2)修改mysql数据库配置,把默认字符集改成utf8,接着修改mysql连接校对为utf8

三个My SQL的系统变量是:

(1)character_set_client,终端字符集,告诉Server客户端提交的SQL语句的编码格式

(2)character_set_connection,连接字符集,是服务器翻译SQL语句时用到的编码格式

(3)character_set_results,返回的结果集的字符集,是服务器返回结果集之前把结果集转换成的编码格式

把这3个系统变量指定成utf8

3)创建数据库时指定字符集utf8,创建数据表时指定字符集utf8,字段也指定成utf8。

4.1.3 建立文件夹乱码

Windows默认字符集是GBK,数据库中取出的数据(utf8)用来创建文件夹时,要经过编码转换,把utf8转换GBK才能正常创建文件目录,否则会出现乱码,目录无法解析。

5 关键技术

5.1 Ajax On Rails

一般来说,对web页面的内容进行修改涉及的工作是用户执行某些操作,然后等待服务器向浏览器返回一个新的页面。AJAX采用向服务器发送异步调用的方法,实现只对页面的一部分进行更新,而不是传统的完成刷新。Rails中集成了Ajax技术,故不需要开发人员自己创建XMLHttpRequest对象、自己写各种复杂的函数,而是通过调用Rails中集成的Ajax机制,方便地实现各种效果。

Rails拥有一个简单的一致性模型来实现Ajax操作。

一旦浏览器生成并显示了起始web页面,不同的用户操作要求它显示一个新的web页面(就像任何传统型的web应用程序)或触发一个Ajax操作:

1)发生一个触发器行动。这可能是用户点击一个按钮或一个超级链接或者用户改变了表单中的数据或字段中的数据,或只是一个周期的触发器(基于一个定时器)。

2)与触发器相联系的数据(一个字段或一个完整的表单)经由XMLHttpRequest被异步地发送到服务器上的一个行动处理器。

3)服务器端行动处理器基于这些数据采取一些行动(这就是为什么称为一个行动处理器),并且返回一个HTML片断作为它的响应。

4)客户端JavaScript(由Rails自动地创建)收到该HTML片断并且使用它更新当前HTML页面指定的部分,经常是一个

标签的内容[7]。

6 结束语

本系统是基于浏览器的辅助教学系统,在现有的辅助教学系统的基础上更加强调自动化管理,师生交流互动。通过该系统能够强化学生的上机积极性,对学生的实践进行量化管理,改变过去上机管理的无序、混乱的状况,达到良好的上机效果。系统平台的选择使得开发者能迅速开发适应实际需要的系统,同时非专业用户也能流利操作,维护简单。

摘要:为大幅度缩短针对新的教学需求的计算机辅助教学系统的开发周期,同时高效的维护系统,研究了当前流行的Ruby On Rails框架技术。基于模型-视图-控制器(model-view-controller,MVC)设计模式进行系统开发,该系统可实现注册登录、作业提交、上机管理、上机测验、发送邮件、信息查询、作业检查、密码提醒等功能。测试结果表明了该软件的实用性。

关键词:辅助教学,MVC,AJAX,Ruby,Rails,Web

参考文献

[1]李艺.计算机辅助教学的概念、实践及其他[J].中国电化教育,1999(9):5-8.

[2]赵伟庆,孙亚飞,戴丽鹃.基于WEB的计算机基础课辅助实验教学系统的应用研究[J].西南民族大学学报:自然科学版,2009,35(6):1285-1288.

[3]扬丽萍.远程计算机辅助教学系统的设计[J].上海海运学院学报,2001,22(4):76-79.

[4]王准,夏阳.基于Ruby on Rails的WEB开发新技术[J].微计算机信息,2007,23(10-3):218-220.

[5]王莉.Rails框架在Web开发中的研究与应用[D].大连:大连海事大学,2008.

[6]孙奇.基于MVC模式的Web开发框架Ruby on Rails的研究[D].北京:北京交通大学,2009.

[7]张迪.基于Ajax框架和MVC设计模式的Web应用研究[D].上海:华东师范大学,2008.

rails 篇5

随着网络的日益普及, 对电子商务和电子政务的需求日趋丰富, 越来越多的企业和政府部门都希望将日常管理逐步信息化和网络化。在这种背景下, 开发者迫切需要一种能够简化开发过程, 降低开发难度, 提高开发效率的框架。目前在Web开发平台中人们使用最多的是Sun公司推出的J2EE。J2EE的问题是随着需求的多样化, 不断加入的各种组件和各种各样数量不断增加、体积不断膨胀的XML配置管理文件使得J2EE应用体系变得臃肿不堪, 在开发和运行速度上越来越不能满足开发者的需求。

而Rails的出现解决了J2EE中各种各样的X M L配置管理文件对开发人员的困扰。Rails是基于Ruby语言的Web应用开发框架, 该框架的最大特点是“约定优先配置”, 和目前其它的一些MVC框架比较, 它不需要繁琐复杂以及数量众多的配置文件, 它已经订立了一系列使用该框架时要遵守的约定, 只要开发人员遵守这些约定, 那么可以实现零配置的M V C框架的web应用, 极大的降低了使用该框架的难度。

Web应用的开发离不开用户界面的设计和开发。在以往的用户界面开发中, 主要使用Javascript脚本语言作为界面互动的开发工具, 但Javascript脚本语言存在编写困难、难于理解以及调试困难的缺点, 所以众多Javascript框架被开发出来以提供对Javascript的包装, 使之功能增强、代码易于理解, 这些J a v a s c r i p t框架包括prototype、Moo Tools、dojo、j Query等。其中j Query是较晚出现的Javascript框架, 但是j Query以其先进的技术、优秀的代码组织、强大的扩展能力, 迅速得到了广大web应用开发人员的青睐。

2 开发工具简介

2.1 Rails介绍

Rails框架是一个MVC结构的框架, 它将应用程序分成如下3个组件:

*模型 (Model) 处理数据和业务逻辑;

*控制器 (Controller) 处理用户接口和应用逻辑;

*视图 (View) 处理图形用户接口对象和表示逻辑。

W e b应用程序的M V C模型组件关系如图1所示, 具体的处理过程如下:

(1) 客户端的浏览器向服务器上的控制器发送页面请求;

(2) 控制器处理相应的请求, 以对象的方式从模型中获得所需要的数据对象;

(3) 控制器将获得的数据对象发送给特定的视图;

(4) 视图向客户端发送页面以便浏览器显示。

Rails实现了模型、视图和控制器概念的完全分离, 它将各部分的代码分别存储在不同目录下的不同文件中。

Rails会自动创建项目的目录结构, 其中存放系统代码的app目录的目录结构如图2所示, 从目录名称就可以看到不同模块的文件被放到了不同的目录中, 这里Rails的“约定优先配置”的思想得到了体现。

2.2 j Query介绍

j Query是继prototype之后的又一个优秀的Javascript框架。它是由John Resig于2 0 0 6年初创建的, 它有助于简化Javascript以及Ajax编程, 方便用户在网页上简单的操作文档、处理事件、实现特效并为Web页面添加Ajax交互。

它具有如下一些特点:

(2) 代码简练、语义易懂、学习快速、文档丰富。

(2) j Query是一个轻量级的脚本, 其代码非常小巧。

(3) j Query支持CSS1-CSS3, 以及基本的x Path。

(4) j Query是跨浏览器的, 它支持的浏览器包括IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+。

(5) 可以很容易的为j Query扩展其他功能。

(6) 能将JS代码和HTML代码完全分离, 便于代码和维护和修改。

(7) 插件丰富, 除了j Query本身带有的一些特效外, 可以通过插件实现更多功能, 如表单验证、tab导航、拖放效果、表格排序、Data Grid, 树形菜单、图像特效以及ajax上传等。

3 开发实例

项目具体需求如下:为满足消防工作信息化管理的要求, 当地消防主管部门需对辖区消防责任单位生成带有文号的消防检查表, 然后将检查结果输入系统, 系统将根据检查结果决定是否生成整改通知书, 整改通知书的内容与检查结果有关。

首先, 经过分析, 系统内的各个成员的关系如图3所示。

第二步, 根据模型的属性, 创建数据库以及相关联的model。Rails中, 数据库的创建不再是直接访问数据库, 而是使用一直叫做Migration的技术, 由rails系统根据Migrate文件内容自动维护数据表结构。例如对于Police类, 和Check Paper类可以使用如下命令生成数据库Migration:

然后再使用命令:

rake db:migrate

即可自动根据Migration文件的内容创建数据表。

在models目录中会自动创建police.rb文件, 该文件是Police类的定义文件, Rails会自动将数据表中的字段映射称类中的属性, 在程序中直接使用Police类对象就可以访问数据库中的内容, 用户无需直接同数据表打交道。

从模型图中可以看出P o l i c e类和Check Paper类是一对多的关系, 为表达这种关系, 并在程序代码中直接使用police.check_papers语句来访问某位民警所管理的所以消防检查表, 需要在创建Check Paper类的Migration的命令中加入“police_id:integer”, 然后在police.rb类文件中加入代码:

同时在check_paper.rb类文件中加入代码:

第三步, 创建控制器。创建一个Police控制器, 用于对浏览器发送的请求进行响应。

此时会在c o n t r o l l e r s目录下创建police_controller.rb文件, 该文件中有一个Police Controller类, 类中有一个index方法, 对应浏览器发送过来的index请求。当浏览器的地址栏中输入“h t t p://localhost:3000/police/index”时, Rails会将该请求解析为访问police控制器中的index方法。系统执行完index方法之后会将数据传递给views目录下的police目录下的index.html.erb文件去进行渲染, 客户端浏览器上呈现的内容就和此文件有关, 此文件就是View。

以后要添加新的响应, 就只需要在对应的控制器文件中加入相应的方法, 并在对应目录下创建视图文件就行了。

Rails框架不需要任何额外的配置, 只要开发人员遵守相应的文件名约定, 文件所在目录的约定, 就可以迅速根据需求写出完美的MVC代码, 极大地简化和加快了开发的过程。

Web应用的用户界面的交互功能采用j Query来完成, 例如在输入检查表结果的页眉中, 有20多个单选组要求选择, 所有的单选组都必须要输入数据, 不能留空。在使用普通Javascript来进行网页校验的情况下要针对每个单选组绑定事件, 代码编写复杂, 容易出错。而使用jquery来进行网页校验时, 只需要引入相应的j Query的validate插件, 然后在页面中插入下列Javascript代码:

针对每个单选组 (如n a m e为check_options_9的单选组) , 编写代码:

则可以完成网页的校验功能。图4中演示了没有选择时出现的错误提示信息, 选择了之后, 出错信息自动消失的情况。

4 结语

项目组充分利用了Rails框架和j Query框架在Web应用上快速开发能力, 仅用了短短5天时间, 完成了从需求分析到系统上线的敏捷式开发过程。目前该系统已在武汉某区公安分局上线使用, 在已上线的6个多月期间内系统运行平稳可靠, 月平均处理业务单270多份。该系统的上线将原来繁复的消防整改处理变得清晰有序, 大大提高了消防管理部门的信息化水平和工作效率。

下一步项目组将根据需求方的要求, 结合多种A j a x快速开发工具实现面向Web应用敏捷式开发, 将主要从完善页面交互效率、友好性、以及后台数据处理效率等方面持续改进系统功能和性能。

摘要:随着网络的日益普及, 对电子商务和电子政务的需求日趋丰富, 越来越多的企业和政府部门都希望将日常管理逐步信息化和网络化。在这种背景下, 如何快速构建网页应用程序, 以最短的时间, 最少的投资, 取得最好的效果, 成为Web应用开发人员迫切希望解决的问题。本文提出了一种开发方法, 用Rails框架快速开发web应用的功能, 用jQuery完善Web应用界面, 实现web应用程序的快速开发。

关键词:Web应用,Rails,框架,Javascript,jQuery

参考文献

[1] Advanced Rails Recipes, Mike Clark, Pragmatic Bookshelf, 2008.

[2] Agile Web Development with Rails Third Edition, Sam Ruby/Dave Thomas/David Hansson/David Heinemeier Hansson, Pragmatic Bookshelf, 2009.

[3] Learning jQuery, Jonathan Chaf-fer/Karl Swedberg, Packt Publishing, 2007.

[4] jQuery in Action, Bear Bibeault /Yehuda Kat, Manning Publications, 2008.

rails 篇6

随着CMOS工艺尺寸和电源电压越来越小, 数字电路的速度得到提高并且功耗也越来越小。但是对于模拟电路来说, 由于阈值电压并没有随之降低多少, 使得电压余度降低, 输入输出摆幅下降, 信噪比降低。在低压环境下, 对于模拟电路的基本模块之一运算放大器就应当尽可能使其输入输出达到轨到轨来提高信噪比。为了能够得到稳定的频率补偿信号, 在整个输入共模范围内跨导应该保持不变。沟道长度的减小使得每个晶体管的本证增益gmr0减小, 为了得到更大的增益提高运放的线性度只能采用三级或者更多级结构。本文给出了一种三级恒跨导运放的设计方法, 并且输入输出都可以达到全摆幅。

1运算放大器整体结构

运算放大器的整体结构如图1所示, 输入端为两个折叠共源共栅级并联, 共模输入范围包括了正负电源电压, 中间级为两个以电流镜为负载的差分运算放大器, 并且同向驱动输出级使其具有推挽特性。晶体管M 23—M 33使电路具有恒跨导特性。外部电压Vref用来设置恒跨导的开关点[1]。电容Ccn (n=1, 2, 3, 4) 用于米勒补偿, 其串联电阻Rn (n=1, 2, 3, 4) 用于抵消米勒补偿产生的右半平面零点, 增大相位裕度。源极负反馈电阻Rs1和Rs2被用于减小晶体管M 5, M 6和M 7, M 8的等效跨导从而消除由这些晶体管引入的输入失调电压[2]。

1.1输入级Rail-Rail的实现

放大器的输入级采用互补折叠式共源共栅结构。折叠式共源共栅运放的一个重要特点就是, 可使输入共模电平接近电源供给的一端电压[3]。M 1和M 2的栅极共模电平可以等于VDD, 因为VX=VY=VDD-VOV。同理PMOS输入对可使输入共模电平低到0伏。所以互补差分输入级使输入共模电压达到Rail-Rail。

1.2跨导恒定原理

使晶体管工作在弱反型区不仅可以降低电源电压, , 还可以提高电源利用率[4]。由公式

可知跨导正比于电流。若在整个共模输入范围内维持一个恒定的总电流就可以提供一个恒定的总跨导。由于PMOS管和NMOS管的n因子不同, 所以必须尽力去补偿n因子的差异性, 否则会引起跨导误差。

如图3[5]所示。在输入电压接近Vref的情况下, 四个输入MOS管都具有相同的电流IB。流经晶体管Mr是2IB, 为电流源电流4IB的一半。在这里Mr相当于一个电流开关。

在较低的输入电压下, NMOS输入对是截止的, 所有4IB的电流通过晶体管Mr。所以PMOS输入对的电流增加了一倍, 所以跨导也增加了一倍。

在较高的输入电压下, PMOS输入对是截止的。此时4IB的电流全部流过NMOS输入对, NMOS上的电流和跨导都放大了一倍。顶端PMOS电流镜用来补偿n因子的差异。

1.3 中间级和AB类输出级

为了达到Rail-Rail输出, 同时增强驱动能力和提高电源效率, 输出方式采用AB类输出, 所以输出晶体管必须同向驱动。对于三级运放的中间级必须是同向运算放大器, 否则由于补偿电容的存在将提供正反馈, 使电路不稳定。在这里中间级为两个并列的以电流镜为负载的差分运算放大器, 第一级运放的差分输出经过这两个差分放大器, 输出变为同向。

2 仿真结果

整个电路采用0.35 μm CMOS工艺参数进行设计, 经过HSPICE工具仿真得到图4所示的频率响应曲线。整个电路在3.0 V的低电源电压下工作, 当电路负载为10 kΩ和5 pF电容负载时电路直流增益达到110 dB, 相位裕度为70°, 单位增益带宽为45 MHz。

3 结束语

电源电压的降低使运算放大器的输入输出摆幅下降, 信噪比降低, 利用电流开关控制的互补差分输入级, 实现了恒定跨导的Rail-Rail输入级提高了输入共模范围。输入差分对工作在弱反型区, 所以更容易工作在低压环境下, 并且提高了电源利用率。高增益特性使其在应用时具有更好的线性度。

参考文献

[1] Tomasik J M, Hafkemeyer K M.A130 nm programmable operationalamplifier.IEEE Journal of Solid-state Circuit, 2008;1 (2) :

[2]胡晶晶.适合宽范围容性负载多级运算放大器频率补偿方法的研究.http://www.cnki.net/2007 pdf

[3]毕查德.拉扎维.模拟CMOS集成电路设计.陈贵灿, 等译.西安:西安交通大学出版社, 2005

[4] Allen P E.CMOS模拟集成电路设计 (第二版) .冯军, 李智群, 译.北京:电子工业出版社, 2007

【rails】推荐阅读:

上一篇:教学改革下的大学体育下一篇:自体动静脉内瘘术

本站热搜

    相关推荐