package org.magnum.mobilecloud.video.controller; import java.util.Collection; import org.magnum.mobilecloud.video.client.VideoSvcApi; import org.magnum.mobilecloud.video.repositorywithoutonetomany.Category2; import org.magnum.mobilecloud.video.repositorywithoutonetomany.CategoryRepository2; import org.magnum.mobilecloud.video.repositorywithoutonetomany.Video2; import org.magnum.mobilecloud.video.repositorywithoutonetomany.VideoRepository2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import com.google.common.collect.Lists; /** * This simple VideoSvc allows clients to send HTTP POST requests with * videos that are stored in memory using a list. Clients can send HTTP GET * requests to receive a JSON listing of the videos that have been sent to * the controller so far. Stopping the controller will cause it to lose the history of * videos that have been sent to it because they are stored in memory. * * Notice how much simpler this VideoSvc is than the original VideoServlet? * Spring allows us to dramatically simplify our service. Another important * aspect of this version is that we have defined a VideoSvcApi that provides * strong typing on both the client and service interface to ensure that we * don't send the wrong paraemters, etc. * * This version of the VideoSvc does not use @OneToMany for any of its Video/Category * operations but provides identical functionality to VideoSvc. * * @author jules * */ // Tell Spring that this class is a Controller that should // handle certain HTTP requests for the DispatcherServlet @Controller public class VideoSvc2 { // The VideoRepository that we are going to store our videos // in. We don't explicitly construct a VideoRepository, but // instead mark this object as a dependency that needs to be // injected by Spring. Our Application class has a method // annotated with @Bean that determines what object will end // up being injected into this member variable. // // Also notice that we don't even need a setter for Spring to // do the injection. // @Autowired private VideoRepository2 videos; @Autowired private CategoryRepository2 categories; // Receives POST requests to /video and converts the HTTP // request body, which should contain json, into a Video // object before adding it to the list. The @RequestBody // annotation on the Video parameter is what tells Spring // to interpret the HTTP request body as JSON and convert // it into a Video object to pass into the method. The // @ResponseBody annotation tells Spring to conver the // return value from the method back into JSON and put // it into the body of the HTTP response to the client. // // The VIDEO_SVC_PATH is set to "/video" in the VideoSvcApi // interface. We use this constant to ensure that the // client and service paths for the VideoSvc are always // in synch. // @RequestMapping(value= "/2" + VideoSvcApi.VIDEO_SVC_PATH, method=RequestMethod.POST) public @ResponseBody boolean addVideo(@RequestBody Video2 v){ // The approach without @OneToMany requires us to do a little bit more // work to check and ensure that the specified Category actually exists // before we save a Video. If we use @OneToMany, JPA automatically ensures // that a Category referenced by a Video exists. if(categories.findOne(v.getCategory()) == null){ throw new RuntimeException("Unknown category:"+v.getCategory()); } videos.save(v); return true; } // Receives POST requests to /category and converts the HTTP // request body, which should contain json, into a Category // object before adding it to the list. The @RequestBody // annotation on the Category parameter is what tells Spring // to interpret the HTTP request body as JSON and convert // it into a Category object to pass into the method. The // @ResponseBody annotation tells Spring to convert the // return value from the method back into JSON and put // it into the body of the HTTP response to the client. // // The VIDEO_SVC_PATH is set to "/video" in the VideoSvcApi // interface. We use this constant to ensure that the // client and service paths for the VideoSvc are always // in synch. // @RequestMapping(value= "/2" + VideoSvcApi.CATEGORY_SVC_PATH, method=RequestMethod.POST) public @ResponseBody boolean addCategory(@RequestBody Category2 c){ categories.save(c); return true; } // Receives GET requests to /video and returns the current // list of videos. Spring automatically converts // the list of videos to JSON because of the @ResponseBody // annotation. @RequestMapping(value= "/2" + VideoSvcApi.VIDEO_SVC_PATH, method=RequestMethod.GET) public @ResponseBody Collection<Video2> getVideoList(){ return Lists.newArrayList(videos.findAll()); } // Receives GET requests to /video/{category} and returns the current // list of videos that are part of the specified category. @RequestMapping(value= "/2" + VideoSvcApi.VIDEO_SVC_PATH+"/{category}", method=RequestMethod.GET) public @ResponseBody Collection<Video2> getVideoListForCategory(@PathVariable("category") String categoryName){ return Lists.newArrayList(videos.findByCategory(categoryName)); } // Receives GET requests to /video/find and returns all Videos // that have a title (e.g., Video.name) matching the "title" request // parameter value that is passed by the client @RequestMapping(value= "/2" + VideoSvcApi.VIDEO_TITLE_SEARCH_PATH, method=RequestMethod.GET) public @ResponseBody Collection<Video2> findByTitle( // Tell Spring to use the "title" parameter in the HTTP request's query // string as the value for the title method parameter @RequestParam(VideoSvcApi.TITLE_PARAMETER) String title ){ return videos.findByName(title); } }