前后端分离了,然后呢?
- - ITeye资讯频道前后端分离已经是业界所共识的一种开发/部署模式了. 关于前后端开发的另一个讨论可以参考这里. 即使通过API来解耦前端和后端开发过程,前后端通过RESTFul的接口来通信,前端的静态内容和后端的动态计算分别开发,分别部署,集成仍然是一个绕不开的问题 — 前端/后端的应用都可以独立的运行,但是集成起来却不工作.
[
{
"id": 1,
"url": "http://abruzzi.github.com/2015/03/list-comprehension-in-python/",
"title": "Python中的 list comprehension 以及 generator",
"publicDate": "2015年3月20日"
},
{
"id": 2,
"url": "http://abruzzi.github.com/2015/03/build-monitor-script-based-on-inotify/",
"title": "使用inotify/fswatch构建自动监控脚本",
"publicDate": "2015年2月1日"
},
{
"id": 3,
"url": "http://abruzzi.github.com/2015/02/build-sample-application-by-using-underscore-and-jquery/",
"title": "使用underscore.js构建前端应用",
"publicDate": "2015年1月20日"
}
]
$(function() {
$.get('/mocks/feeds.json').then(function(feeds) {
var feedList = new Backbone.Collection(extended);
var feedListView = new FeedListView(feedList);
$('.container').append(feedListView.render());
});
});
get '/api/feeds' do
content_type 'application/json'
File.open('mocks/feeds.json').read
end
[
{
"id": 3,
"url": "http://abruzzi.github.com/2015/02/build-sample-application-by-using-underscore-and-jquery/",
"title": "使用underscore.js构建前端应用",
"publicDate": "2015年1月20日"
}
]
get '/api/fav-feeds/:id' do
content_type 'application/json'
File.open('mocks/fav-feeds.json').read
end
$.when(feeds, favorite).then(function(feeds, favorite) {
var ids = _.pluck(favorite[0], 'id');
var extended = _.map(feeds[0], function(feed) {
return _.extend(feed, {status: _.includes(ids, feed.id)});
});
var feedList = new Backbone.Collection(extended);
var feedListView = new FeedListView(feedList);
$('.container').append(feedListView.render());
});
toggleFavorite: function(event) {
event.preventDefault();
var that = this;
$.post('/api/feeds/'+this.model.get('id')).done(function(){
var status = that.model.get('status');
that.model.set('status', !status);
});
}
post '/api/feeds/:id' do end
#encoding: utf-8
require 'spec_helper'
describe 'Feeds List Page' do
let(:list_page) {FeedListPage.new}
before do
list_page.load
end
it 'user can see a banner and some feeds' do
expect(list_page).to have_banner
expect(list_page).to have_feeds
end
it 'user can see 3 feeds in the list' do
expect(list_page.all_feeds).to have_feed_items count: 3
end
it 'feed has some detail information' do
first = list_page.all_feeds.feed_items.first
expect(first.title).to eql("Python中的 list comprehension 以及 generator")
end
end
@Controller
@RequestMapping("/api")
public class FeedsController {
@Autowired
private FeedsService feedsService;
@Autowired
private UserService userService;
public void setFeedsService(FeedsService feedsService) {
this.feedsService = feedsService;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
@RequestMapping(value="/feeds", method = RequestMethod.GET)
@ResponseBody
public Iterable<Feed> allFeeds() {
return feedsService.allFeeds();
}
@RequestMapping(value="/fav-feeds/{userId}", method = RequestMethod.GET)
@ResponseBody
public Iterable<Feed> favFeeds(@PathVariable("userId") Long userId) {
return userService.favoriteFeeds(userId);
}
}
private MockMvc mockMvc;
private FeedsService feedsService;
private UserService userService;
@Before
public void setup() {
feedsService = mock(FeedsService.class);
userService = mock(UserService.class);
FeedsController feedsController = new FeedsController();
feedsController.setFeedsService(feedsService);
feedsController.setUserService(userService);
mockMvc = standaloneSetup(feedsController).build();
}
@Test
public void shouldResponseWithAllFeeds() throws Exception {
when(feedsService.allFeeds()).thenReturn(Arrays.asList(prepareFeeds()));
mockMvc.perform(get("/api/feeds"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$", hasSize(3)))
.andExpect(jsonPath("$[0].publishDate", is(notNullValue())));
}
private Feed[] prepareFeeds() throws IOException {
URL resource = getClass().getResource("/mocks/feeds.json");
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(resource, Feed[].class);
}
@Test
public void shouldResponseWithUsersFavoriteFeeds() throws Exception {
when(userService.favoriteFeeds(any(Long.class)))
.thenReturn(Arrays.asList(prepareFavoriteFeeds()));
mockMvc.perform(get("/api/fav-feeds/1"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].title", is("使用underscore.js构建前端应用")))
.andExpect(jsonPath("$[0].publishDate", is(notNullValue())));
}