Zapraszamy na płatny, wakacyjny staż TouK!
Zgłoszenia przyjmujemy do 17.05.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.1.0.RELEASE</version>
</dependency>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/feed</url-pattern>
</servlet-mapping>
Notice, I set the url-pattern to “/feed” which means I don't want Spring MVC to handle any other urls in my app (I'm using a different web framework for the rest of the app). I also give it a brand new contextConfigLocation, where only the mvc configuration is kept.<dependency>
<groupId>net.java.dev.rome</groupId>
<artifactId>rome</artifactId>
<version>1.0.0</version>
</dependency>
@Controller
public class FeedController {
static final String LAST_UPDATE_VIEW_KEY = "lastUpdate";
static final String NEWS_VIEW_KEY = "news";
private NewsRepository newsRepository;
private String viewName;
protected FeedController() {} //required by cglib
public FeedController(NewsRepository newsRepository, String viewName) {
notNull(newsRepository); hasText(viewName);
this.newsRepository = newsRepository;
this.viewName = viewName;
}
@RequestMapping(value = "/feed", method = RequestMethod.GET)
@Transactional
public ModelAndView feed() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName(viewName);
List<News> news = newsRepository.fetchPublished();
modelAndView.addObject(NEWS_VIEW_KEY, news);
modelAndView.addObject(LAST_UPDATE_VIEW_KEY, getCreationDateOfTheLast(news));
return modelAndView;
}
private Date getCreationDateOfTheLast(List<News> news) {
if(news.size() > 0) {
return news.get(0).getCreationDate();
}
return new Date(0);
}
}
And here's a test for it, in case you want to copy&paste (who doesn't?):@RunWith(MockitoJUnitRunner.class)
public class FeedControllerShould {
@Mock private NewsRepository newsRepository;
private Date FORMER_ENTRY_CREATION_DATE = new Date(1);
private Date LATTER_ENTRY_CREATION_DATE = new Date(2);
private ArrayList<News> newsList;
private FeedController feedController;
@Before
public void prepareNewsList() {
News news1 = new News().title("title1").creationDate(FORMER_ENTRY_CREATION_DATE);
News news2 = new News().title("title2").creationDate(LATTER_ENTRY_CREATION_DATE);
newsList = newArrayList(news2, news1);
}
@Before
public void prepareFeedController() {
feedController = new FeedController(newsRepository, "viewName");
}
@Test
public void returnViewWithNews() {
//given
given(newsRepository.fetchPublished()).willReturn(newsList);
//when
ModelAndView modelAndView = feedController.feed();
//then
assertThat(modelAndView.getModel())
.includes(entry(FeedController.NEWS_VIEW_KEY, newsList));
}
@Test
public void returnViewWithLastUpdateTime() {
//given
given(newsRepository.fetchPublished()).willReturn(newsList);
//when
ModelAndView modelAndView = feedController.feed();
//then
assertThat(modelAndView.getModel())
.includes(entry(FeedController.LAST_UPDATE_VIEW_KEY, LATTER_ENTRY_CREATION_DATE));
}
@Test
public void returnTheBeginningOfTimeAsLastUpdateInViewWhenListIsEmpty() {
//given
given(newsRepository.fetchPublished()).willReturn(new ArrayList<News>());
//when
ModelAndView modelAndView = feedController.feed();
//then
assertThat(modelAndView.getModel())
.includes(entry(FeedController.LAST_UPDATE_VIEW_KEY, new Date(0)));
}
}
Notice: here, I'm using fest-assert and mockito. The dependencies are: <dependency> <groupId>org.easytesting</groupId> <artifactId>fest-assert</artifactId> <version>1.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.8.5</version> <scope>test</scope> </dependency>
import org.springframework.web.servlet.view.feed.AbstractAtomFeedView;
[...]
public class AtomFeedView extends AbstractAtomFeedView {
private String feedId = "tag:yourFantastiSiteName";
private String title = "yourFantastiSiteName: news";
private String newsAbsoluteUrl = "http://yourfanstasticsiteUrl.com/news/";
@Override
protected void buildFeedMetadata(Map<String, Object> model, Feed feed, HttpServletRequest request) {
feed.setId(feedId);
feed.setTitle(title);
setUpdatedIfNeeded(model, feed);
}
private void setUpdatedIfNeeded(Map<String, Object> model, Feed feed) {
@SuppressWarnings("unchecked")
Date lastUpdate = (Date)model.get(FeedController.LAST_UPDATE_VIEW_KEY);
if (feed.getUpdated() == null || lastUpdate != null || lastUpdate.compareTo(feed.getUpdated()) > 0) {
feed.setUpdated(lastUpdate);
}
}
@Override
protected List<Entry> buildFeedEntries(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
@SuppressWarnings("unchecked")
List<News> newsList = (List<News>)model.get(FeedController.NEWS_VIEW_KEY);
List<Entry> entries = new ArrayList<Entry>();
for (News news : newsList) {
addEntry(entries, news);
}
return entries;
}
private void addEntry(List<Entry> entries, News news) {
Entry entry = new Entry();
entry.setId(feedId + ", " + news.getId());
entry.setTitle(news.getTitle());
entry.setUpdated(news.getCreationDate());
entry = setSummary(news, entry);
entry = setLink(news, entry);
entries.add(entry);
}
private Entry setSummary(News news, Entry entry) {
Content summary = new Content();
summary.setValue(news.getShortDescription());
entry.setSummary(summary);
return entry;
}
private Entry setLink(News news, Entry entry) {
Link link = new Link();
link.setType("text/html");
link.setHref(newsAbsoluteUrl + news.getId()); //because I have a different controller to show news at http://yourfanstasticsiteUrl.com/news/ID
entry.setAlternateLinks(newArrayList(link));
return entry;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="atom" value="application/atom+xml"/>
<entry key="html" value="text/html"/>
</map>
</property>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
</list>
</property>
</bean>
<bean class="eu.margiel.pages.confitura.feed.FeedController">
<constructor-arg index="0" ref="newsRepository"/>
<constructor-arg index="1" value="atomFeedView"/>
</bean>
<bean id="atomFeedView" class="eu.margiel.pages.confitura.feed.AtomFeedView"/>
</beans>