@Controller @RequestMapping("/user") public class UserController { @Autowired private UserServcie userService;//接口编程 @RequestMapping(method = RequestMethod.GET) public void sayHello(){ } }
1、@Controller是告诉Spring容器,这是一个控制器类;
2、@RequestMapping("/user")是来定义该控制器对应的请求路径(/user)
3、@Autowired按byType自动注入所需要使用的对象,这样就不需要我们再写get/set方法了(同时,JSR-250标准注解,推荐使用@Resource来代替Spring专有的@Autowired注解。)
---@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。
@Resource有两个属性是比较重要的,分别是name和type,Spring将@Resource注解的name属性解析为bean的名字,
而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。
如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
@Resource装配顺序
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配(见2);如果没有匹配,
则回退为一个原始类型(UserDao)进行匹配,如果匹配则自动装配;
4、@RequestMapping(method = RequestMethod.GET)指定了访问方法类型。
5、@Service用于标识这是一个Service层实现。
6、@Transactional用于控制事务,将事务定位在业务层,这是非常务实的做法。
-------需要在配置文件中添加<tx:annotation-driven transaction-manager="事务名称" />才能起作用
如果事务的名称不是默认的transactionManager,那么在使用@Transactional注解的每个地方都要加上该事务名称
<!-- 事务管理器配置, Hibernate数据源事务(配置自定义的事务管理器) --> <bean id="transactionManagerUsers" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactoryUsers"></property> </bean> <tx:annotation-driven transaction-manager="transactionManager"/>
@Service public class UserServiceImpl implements UserServcie { @Transactional public void saveMessage(){ //.......code.... } @Transactional public void saveTinBod(){ //......code..... } }
那么在调用saveMessage方法的时候,方法saveTinBod的事务是不起作用的,也就是说在同一个类中的方法A调用该类中的其它方法B,B方法定义的事务是不起作用的,
但是如果B方法的事务是通过aop传播配置的,那么B方法的事务还是会起作用
-------spring通过aop传播事务配置:
<!-- AOP注入事务 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- all methods starting with 'get/search/find/load' are read-only --> <tx:method name="get*" read-only="true" propagation="REQUIRES_NEW"/> <tx:method name="search*" read-only="true" propagation="REQUIRES_NEW"/> <tx:method name="find*" read-only="true" propagation="REQUIRES_NEW"/> <tx:method name="loadResourceDefine" read-only="true" propagation="REQUIRES_NEW"/> <!-- other methods use the default transaction settings (see below) --> <tx:method name="*"/> </tx:attributes> </tx:advice> <aop:config> <!-- 事务切入点 --> <aop:pointcut expression="execution(*com..*.*(..))" id="servicePointCut"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointCut"/> </aop:config>
经过测试总结如下
(1)、当一个方法即有配置@Transactional,又包含在spring通过aop传播配置的事务时,@Transactional配置将覆盖spring通过aop传播配置的事务
(2)、当一个类的两个方法A、B,都有注解@Transactional,如果A调用B的话,那么B通过@Transactional配置的事务将不起作用,
但是在B方法上通过springaop传播配置的事务会起作用,可以理解为B方法上没有注解@Transactional事务,所以Aop传播的事务将起作用
7、我们想要在自定义的方法中获得一些个“标准”输入参数,参数类型必须包含在以下类型中:
@Controller @RequestMapping("/user") public class UserController { @Autowired private UserServcie userService;//接口编程 @RequestMapping(method = RequestMethod.GET) public void sayHello(){ } }
ServletRequest、ServletResponse、HttpSession、Principal、Locale、InputStream、OutputStream、Reader、Writer这些参数都是对
HttpServletRequest和HttpServletResponse的扩展。(原因见下面的源码:AnnotationMehtodHandlerAdapter部分源代码)
1.@Override 2.protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) 3. throws Exception { 4. 5. HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); 6. HttpServletResponse response = (HttpServletResponse) webRequest.getNativeResponse(); 7. 8. if (ServletRequest.class.isAssignableFrom(parameterType)) { 9. return request; 10. } 11. else if (ServletResponse.class.isAssignableFrom(parameterType)) { 12. this.responseArgumentUsed = true; 13. return response; 14. } 15. else if (HttpSession.class.isAssignableFrom(parameterType)) { 16. return request.getSession(); 17. } 18. else if (Principal.class.isAssignableFrom(parameterType)) { 19. return request.getUserPrincipal(); 20. } 21. else if (Locale.class.equals(parameterType)) { 22. return RequestContextUtils.getLocale(request); 23. } 24. else if (InputStream.class.isAssignableFrom(parameterType)) { 25. return request.getInputStream(); 26. } 27. else if (Reader.class.isAssignableFrom(parameterType)) { 28. return request.getReader(); 29. } 30. else if (OutputStream.class.isAssignableFrom(parameterType)) { 31. this.responseArgumentUsed = true; 32. return response.getOutputStream(); 33. } 34. else if (Writer.class.isAssignableFrom(parameterType)) { 35. this.responseArgumentUsed = true; 36. return response.getWriter(); 37. } 38. return super.resolveStandardArgument(parameterType, webRequest); 39.}
当然我们还可以自定义参数,自定义参数必须是实现类,Spring容器将帮我们完成对象的初始化工作
1.@RequestMapping(method = RequestMethod.GET) 2.public void hello(String username,String password) { 3. System.out.println(accountService.verify(username, password)); 4.}
如果参数名不能与这里的变量名保持一致,则我们可以使用注解@RequestParam进行强制绑定:
1.@RequestMapping(method = RequestMethod.GET) 2.public void hello(@RequestParam("username") String u, 3. @RequestParam("password") String p) { 4. System.out.println(accountService.verify(u, p)); 5.}
8、我们还可以子能够以即将传出的参数:
这时,我们没有定义页面名称,Spring容器将根据请求名指定同名的view,即如果是jsp页面,则user -- > user.jsp:如下
public Map<String,Object > getMapData(String username,String password,ModelMap model){ model.addAttribute("u", username).addAttribute("p", password); return model; }
通过ModelMap,我们可以绑定输出数据到页面。除此之外,我们还可以定义其他的返回类型:ModelAndView、Model、View、Map、String、null(即对应void类型方法)
9、@Session
如果想将某个ModelMap中的参数指定到Sesseion中,可以使用该注解。
@Controller @RequestMapping("/user") @SessionAttributes("username") public class UserController { @Autowired private UserServcie userService;//接口编程 @RequestMapping(method = RequestMethod.GET) public void sayHello(){ } @RequestMapping("/login") public void sayBye(@RequestParam("username")String u,@RequestParam("password")String p){ } @RequestMapping("/index") public Map<String,Object > getMapData(String username,String password,ModelMap model){ model.addAttribute("u", username).addAttribute("p", password); return model; } }
10、@Repository明确这个类是用于持久层的实现类,注意这样的注解不能用于接口,仅适用于实现类!
11、@InitBinder 由这个注释标识的方法,它初始化WebDataBinder,这个WebDataBinder用于填充被@InitBinder注释的处理方法的command和form对象。
@InitBinder方法支持RequestMapping支持的所有参数,command/form对象和相关校验结果。@InitBinder方法不能有返回值,它必须声明为void。
自定义springMVC的属性编辑器主要有两种方式,一种是使用@InitBinder标签在运行期注册一个属性编辑器,这种编辑器只在当前Controller里面有效;
还有一种是实现自己的 WebBindingInitializer,然后定义一个
AnnotationMethodHandlerAdapter的bean,在此bean里面进行注册
,
这种属性编辑器是全局的。
12、@RequestBody 将HTTP请求正文转换为合适的HttpMessageConverter对象
@ResponseBody将内容或对象作为HTTP响应正文返回,并调用合适HttpMessageConverter的Adapter转换对象,写入输出流。
HttpMessageConverter接口,需要开启<mvc:annotation-driven />。 AnnotationMethodHandlerAdapter将会初始化7个转换器,可以通过调用AnnotationMethodHandlerAdapter的
getMessageConverts()方法来获取转换器的一个集合 List<HttpMessageConverter> 引用 ByteArrayHttpMessageConverter StringHttpMessageConverter ResourceHttpMessageConverter SourceHttpMessageConverter XmlAwareFormHttpMessageConverter Jaxb2RootElementHttpMessageConverter MappingJacksonHttpMessageConverter
可以理解为,只要有对应协议的解析器,你就可以通过几行配置,几个注解完成协议——对象的转换工作! Spring默认的json协议解析由Jackson完成。
13、@PathVariable
当使用@RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvariable注解绑定它传过来的值到方法的参数上。
构建成REST访问风格。
@RequestMapping("/user/{id}")//REST风格 public void findUser(@PathVariable String id,String name){ }
14、@RequestHeader
可以把Request请求header部分的值绑定到方法的参数上。
//示列 //下面为Request请求的header部分: Host localhost:8080 Accept text/html,applicatiojn/xhtml+xml,application.xml; Accept-language en-gb Accept-Charset ISO-8859-1 keep-Alive 300
@RequestMapping("/display") public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding, @RequestHeader("Keep-Alive") String keepAlive){ }
15、@CookieValue
可以把Request请求Header的关于cookie的值绑定到方法的参数上。
@RequestMapping("/cookie") public void getCook(@CookieValue("JSESSIONID")String cookie){ }
16、我们使用@RequestBody @ResponseBody 解决了JSon自动绑定,但是如果遇到RuntimeException需要给出一个默认返回jSON.
springMVC提供的异常统一处理方式
第一种方法可以使用SimpleMappingExceptionResolver拦截实现。
第二种方法:可以使用@ExceptionHandler : 使用该注解进行处理的不好地方时异常处理的方法必须与出错的方法在同一个Controller里面。
@Controller @RequestMapping("/user") @SessionAttributes("username") public class UserController { /** * 该控制器的异常统一处理方式 * 可以指定多个异常 */ @ExceptionHandler({Exception.class,RuntimeException.class}) public Map<String,Object> exception(Exception e){ e.printStackTrace(); Map<String,Object> map = new HashMap<String,Object>(); map.put("status", false); return map; } @RequestMapping("test") public void test(String username){ throw new RuntimeException("运行时异常"); } }
在请求test这个方法时就会报错,而拥有该test方法Controller又拥有一个处理异常的方法,这个时候处理异常的方法就会被调用,
如果同时通过两种方式来配置异常处理,则第一种方式会将第二种方式覆盖。