Spring MVC 3.x annotated controller的几点心得体会
最近拿Spring MVC 3.x做项目,用了最新的系列相关Annotation来做Controller,有几点心得体会值得分享。
转载请注明 :IT进行时(zhengxianquan AT hotmail.com) from
http://itstarting.iteye.com/
一、编写一个AbstractController.java,所有的Controller必须扩展
除了获得Template Design Pattern的好处之外,还能一点,那就是放置全局的@InitBinder:
public class AbstractController {...@InitBinderprotected void initBinder(WebDataBinder binder) {SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");dateFormat.setLenient(false);binder.registerCustomEditor(Date.class,new CustomDateEditor(dateFormat, false));}...}
@Controller@RequestMapping(value = "/hotels")public class HotelsController extends AbstractController {...@RequestMapping(value = "/bookings/cancel/{id}", method = RequestMethod.POST)public String deleteBooking(@PathVariable long id) {bookingService.cancelBooking(id);//use prefix 'redirect' to avoid duplicate submissionreturn "redirect:../../search";}...}
<dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-asl</artifactId><version>1.5.3</version></dependency>
@ResponseBody@RequestMapping(value = "/ajax", method = RequestMethod.POST)public JsonDataWrapper<Hotel> ajax(WebRequest request, Hotel hotel, Model model) throws Exception {JsonDataWrapper<Hotel> jsonDataWrapper = this.getPaginatedGridData(request, hotel, hotelService);return jsonDataWrapper;}
/** * A wrapper class for jQuery Flexigrid plugin component. * * The format must be like this: * <code> * {"total":2,"page":1,"rows":[ * {"personTitle":"Mr","partyName":"Test8325","personDateOfBirth":"1970-07-12"}, * {"personTitle":"Ms","partyName":"Ms Susan Jones","personDateOfBirth":"1955-11-27"} * ]} * </code> * * @author bright_zheng * * @param <T>: the generic type of the specific domain */public class JsonDataWrapper<T> implements Serializable {private static final long serialVersionUID = -538629307783721872L;public JsonDataWrapper(int total, int page, List<T> rows){this.total = total;this.page = page;this.rows = rows;}private int total;private int page;private List<T> rows;public int getTotal() {return total;}public void setTotal(int total) {this.total = total;}public int getPage() {return page;}public void setPage(int page) {this.page = page;}public List<T> getRows() {return rows;}public void setRows(List<T> rows) {this.rows = rows;}}
public class HotelsControllerTest {private static HandlerMapping handlerMapping;private static HandlerAdapter handlerAdapter;private static MockServletContext msc;@BeforeClasspublic static void setUp() {String[] configs = {"file:src/main/resources/context-*.xml","file:src/main/webapp/WEB-INF/webapp-servlet.xml" };XmlWebApplicationContext context = new XmlWebApplicationContext(); context.setConfigLocations(configs); msc = new MockServletContext(); context.setServletContext(msc); context.refresh(); msc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context); ApplicationContextManager manager = new ApplicationContextManager();manager.setApplicationContext(context);handlerMapping = (HandlerMapping) ApplicationContextManager.getContext().getBean(DefaultAnnotationHandlerMapping.class);handlerAdapter = (HandlerAdapter) ApplicationContextManager.getContext().getBean(ApplicationContextManager.getContext().getBeanNamesForType(AnnotationMethodHandlerAdapter.class)[0]);}@Testpublic void list() throws Exception {MockHttpServletRequest request = new MockHttpServletRequest();MockHttpServletResponse response = new MockHttpServletResponse();request.setRequestURI("/hotels");request.addParameter("booking.id", "1002");request.addParameter("hotel.name", "");request.setMethod("POST");//HandlerMappingHandlerExecutionChain chain = handlerMapping.getHandler(request);Assert.assertEquals(true, chain.getHandler() instanceof HotelsController);//HandlerAdapterfinal ModelAndView mav = handlerAdapter.handle(request, response, chain.getHandler());//Assert logicAssert.assertEquals("hotels/search", mav.getViewName());}}
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = {"file:src/main/resources/context-*.xml" })public class DefaultServiceImplTest {/** @Autowired works if we put @ContextConfiguration at junit type */@Autowired@Qualifier("hotelService")private HotelService<Hotel> hotelService;@Testpublic void insert() {Hotel hotel = new Hotel();hotel.setAddress("addr");hotel.setCity("Singapore");hotel.setCountry("Singapore");hotel.setName("Great Hotel");hotel.setPrice(new BigDecimal(200));hotel.setState("Harbarfront");hotel.setZip("010024");hotelService.insert(hotel);}}
public class AclInterceptor extends HandlerInterceptorAdapter {private static final Logger logger = Logger.getLogger(AclInterceptor.class);/** default servlet prefix */private static final String DEFAULT_SERVLET_PREFIX = "/servlet";/** will be injected from context configuration file */private AclService service;@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {String currentUri = request.getRequestURI();boolean isAccessible = true;//only intercept for annotated business controllersController c = AnnotationUtils.findAnnotation(handler.getClass(), Controller.class);if(c!=null){String[] grantedResource = getGrantedResource(request);if(grantedResource==null || grantedResource.length==0){throw new AccessDeniedException("No resource granted");}isAccessible = service.isAccessible(grantedResource, currentUri);if(logger.isDebugEnabled()){logger.debug("ACL interceptor excueted. Accessible for Uri[" + currentUri +"] = " + isAccessible);}//if isAccessible==true, throw custom AccessDeniedExceptionif(!isAccessible) throw new AccessDeniedException();}return isAccessible;}/** * transfer the original Uri to resource Uri * e.g.: * original Uri: /servlet/hotels/ajax * target Uri : /hotels/ajax * @param originalUri * @return */protected String getUri(String originalUri){return originalUri.substring(DEFAULT_SERVLET_PREFIX.length());}/** * Get the granted resource from session * @param request * @return */protected String[] getGrantedResource(HttpServletRequest request){//get the resources from current session//String[] uriResourcePattern = (String[]) request.getSession().getAttribute("uriResourcePattern");//TODO: mock data hereString[] uriResourcePattern = new String[]{"/**"};return uriResourcePattern;}public void setService(AclService service) {this.service = service;}}