admin管理员组文章数量:1794759
Spring SpringMVC SpringBoot 常用注解说明
Spring SpringMVC SpringBoot 常用注解说明
- Spring
- 注解与xml配置的区别
- 不使用注解的案例
- @Autowired
- @Qualifier
- @Resource
- @Service
- 使用注解来构造IoC容器
- @Component
- @Controller
- @Service
- @ Repository
- Spring常用注解汇总
- Spring MVC
- @Controller
- @RequestMapping
- 使用 @RequestMapping 来映射 Request 请求与处理器
- 方式一:通过常见的类路径和方法路径结合访问controller方法
- 方式二:使用uri模板
- 使用 @RequestMapping 的一些高级用法
- params属性
- method属性
- headers属性
- @RequestMapping 标记的处理器方法支持的方法参数和返回类型
- 支持的方法参数类型
- 支持的返回类型
- @ModelAttribute和 @SessionAttributes
- @PathVariable
- @requestParam
- @ResponseBody
- handler method 参数绑定常用的注解
- 处理requet uri 部分(这里指uri template中variable,不含queryString部分)的注解:@PathVariable;
- 处理request header部分的注解: @RequestHeader, @CookieValue;
- 处理request body部分的注解:@RequestParam, @RequestBody;
- 处理attribute类型是注解: @SessionAttributes, @ModelAttribute;
- < context:component-scan base-package = "" />浅析
- Spring Boot
- @SpringBootApplication
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
- @RestController
- RequestMapping简化注解
- @Profiles
- 全局异常处理
Spring使用.xml配置来注入或者配置Aop,事务,主要缺点有两个:
定义老虎
public class Tiger { private String tigerName="Tiger"; public String toString(){ return "TigerName:"+tigerName; } }定义猴子
public class Monkey { private String monkeyName = "Monkey"; public String toString(){ return "MonkeyName:" + monkeyName; } }定义动物园
public class Zoo { private Tiger tiger; private Monkey monkey; public Tiger getTiger() { return tiger; } public void setTiger(Tiger tiger) { this.tiger = tiger; } public Monkey getMonkey() { return monkey; } public void setMonkey(Monkey monkey) { this.monkey = monkey; } public String toString(){ return tiger + "\\n" + monkey; } }Spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xmlns:p="www.springframework/schema/p" xmlns:context="www.springframework/schema/context" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans-3.0.xsd www.springframework/schema/context www.springframework/schema/context/spring-context-3.0.xsd "> <bean id="zoo" class="com.spring.Zoo" > <property name="tiger" ref="tiger" /> <property name="monkey" ref="monkey" /> </bean> <bean id="tiger" class="com.spring.Tiger" /> <bean id="monkey" class="com.spring.Monkey" /> </beans>测试方法(不使用注解)
public class TestAnnotation { @Test public void test(){ //读取配置文件 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); Zoo zoo=(Zoo) ctx.getBean("zoo"); System.out.println(zoo.toString()); } } @Autowired@Autowired自动装配,其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property。 getter看个人需求,如果私有属性需要对外提供的话,应当予以保留 @Autowired默认按类型匹配的方式,在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。
因此,引入@Autowired注解,先看一下spring配置文件怎么写:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xmlns:p="www.springframework/schema/p" xmlns:context="www.springframework/schema/context" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans-3.0.xsd www.springframework/schema/context www.springframework/schema/context/spring-context-3.0.xsd "> //告知spring要使用注解了,spring会自动扫描com.spring路径下的注解 <context:component-scan base-package="com.spring" /> <bean id="zoo" class="com.spring.Zoo" /> <bean id="tiger" class="com.spring.Tiger" /> <bean id="monkey" class="com.spring.Monkey" /> </beans>原来zoo里面应当注入两个属性tiger、monkey,现在不需要注入了。再看下,Zoo.java也很方便,把getter/setter都可以去掉:
public class Zoo { @Autowired private Tiger tiger; @Autowired private Monkey monkey; public String toString(){ return tiger + "\\n" + monkey; } }这里@Autowired注解的意思就是,当Spring发现@Autowired注解时,将自动在代码上下文中找到和其匹配(默认是类型匹配)的Bean,并自动注入到相应的地方去。 有一个细节性的问题是,假如bean里面有两个property,Zoo.java里面又去掉了属性的getter/setter并使用@Autowired注解标注这两个属性那会怎么样?答案是Spring会按照xml优先的原则去Zoo.java中寻找这两个属性的getter/setter,导致的结果就是初始化bean报错。
假设把xml配置中,下面两行去掉,再运行,会抛出异常:
<bean id="tiger" class="com.spring.Tiger" /> <bean id="monkey" class="com.spring.Monkey" /> org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'zoo': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.spring.model.Tiger com.spring.model.Zoo.tiger; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.spring.model.Tiger] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}因为,@Autowired注解要去寻找的是一个Bean,Tiger和Monkey的Bean定义都给去掉了,自然就不是一个Bean了,Spring容器找不到也很好理解。那么,如果属性找不到我不想让Spring容器抛出异常,而就是显示null,可以吗?可以的,其实异常信里面也给出了提示了,就是将==@Autowired注解的required属性设置为false即可==:
public class Zoo { @Autowired(required=false) private Tiger tiger; @Autowired(required=false) private Monkey monkey; public String toString(){ return tiger + "\\n" + monkey; } }此时,找不到tiger、monkey两个属性,Spring容器不再抛出异常而是认为这两个属性为null。
@Qualifier如果容器中有一个以上匹配的Bean,则可以通过@Qualifier注解限定Bean的名称,看下面的例子: 定义一个Phone接口:
public interface IPhone{ public String getPhoneName(); }两个实现类xiaomiPhone和huaweiPhone:
public class xiaomiPhone implements IPhone{ public String getPhoneName(){ return "xiaomi Phone"; } } public class huaweiPhoneimplements IPhone{ public String getPhoneName(){ return "huawei Phone"; } }再写一个PhoneFactory,引用Iphone(这里先不用@Qualifier注解):
public class CarFactory { @Autowired private IPhone phone; public String toString(){ return phone.getPhoneName(); } }配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xmlns:p="www.springframework/schema/p" xmlns:context="www.springframework/schema/context" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans-3.0.xsd www.springframework/schema/context www.springframework/schema/context/spring-context-3.0.xsd "> <context:component-scan base-package="com.spring" /> <!-- Autowired注解配合Qualifier注解 --> <bean id="PhoneFactory" class="com.spring.PhoneFactory" /> <bean id="xiaomiPhone" class="com.spring.service.impl.xiaomiPhone" /> <bean id="huaweiPhone" class="com.spring.service.impl.huaweiPhone" /> </beans>测试方法:
/** * Autowired注解配合Qualifier注解 */ @Test public void test1(){ //读取配置文件 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); PhoneFactory phoneFactory=(PhoneFactory) ctx.getBean("PhoneFactory"); System.out.println(phoneFactory.toString()); }运行一下,不用说,一定是报错的,Phone接口有两个实现类,Spring并不知道应当引用哪个实现类。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'phoneFactory': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.spring.IPhone com.spring.PhoneFactory.car; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.spring.IPhone ] is defined: expected single matching bean but found 2: [xiaomiPhone, huaweiPhone]出现这种情况通常有两种解决办法: (1)、在配置文件中删除其中一个实现类,Spring会自动去base-package下寻找Phone接口的实现类,发现Phone接口只有一个实现类,便会直接引用这个实现类。 (2)、实现类就是有多个该怎么办?此时可以使用@Qualifier注解来指定Bean的名称: 此处会注入名为"xiaomiPhone"的Bean
public class PhoneFactory { @Autowired @Qualifier("xiaomiPhone") private IPhone phone; public String toString(){ return phone.getPhoneName(); } } @Resource@Resource注解与@Autowired注解作用非常相似,这个就简单说了,看例子:
public class Zoo1 { @Resource(name="tiger") private Tiger tiger; @Resource(type=Monkey.class) private Monkey monkey; public String toString(){ return tiger + "\\n" + monkey; } }@Resource的装配顺序:
@Autowired和@Resource两个注解的区别:
Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。
@Service上面这个例子,还可以继续简化,因为spring的配置文件里面还有三个bean,下一步的简化是把这三个bean也给去掉,使得spring配置文件里面只有一个自动扫描的标签,增强Java代码的内聚性并进一步减少配置文件。 要继续简化,可以使用@Service。先看一下配置文件,当然是全部删除了:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xmlns:p="www.springframework/schema/p" xmlns:context="www.springframework/schema/context" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans-3.0.xsd www.springframework/schema/context www.springframework/schema/context/spring-context-3.0.xsd "> <context:component-scan base-package="com.spring" /> </beans>以Zoo.java为例,其余的Monkey.java和Tiger.java都一样:
@Service public class Zoo { @Autowired private Tiger tiger; @Autowired private Monkey monkey; public String toString(){ return tiger + "\\n" + monkey; } }Zoo.java在Spring容器中存在的形式就是"zoo",即可以通过ApplicationContext的getBean(“zoo”)方法来得到Zoo.java。@Service注解,其实做了两件事情:
如果,我不想用这种形式怎么办,就想让Zoo.java在Spring容器中的名字叫做"Zoo",可以的:
@Service("Zoo") @Scope("prototype") public class Zoo { @Autowired private Tiger tiger; @Autowired private Monkey monkey; public String toString(){ return tiger + "\\n" + monkey; } }这样,就可以通过ApplicationContext的getBean(“Zoo”)方法来得到Zoo.java了。
@Scope注解,应该很好理解。因为Spring默认产生的bean是单例的,假如我不想使用单例怎么办,xml文件里面可以在bean里面配置scope属性。注解也是一样,配置@Scope即可,默认是"singleton"即单例,"prototype"表示原型即每次都会new一个新的出来。
使用注解来构造IoC容器用注解来向Spring容器注册Bean。需要在applicationContext.xml中注册<context:component-scan base-package=”pagkage1[,pagkage2,…,pagkageN]”/>
<context:component-scan base-package=“cn.gacl.java”/>
表明cn.gacl.java包及其子包中,如果某个类的头上带有特定的注解【@Component/@Repository/@Service/@Controller】,就会将这个对象作为Bean注册进Spring容器。也可以在<context:component-scan base-package=” ”/>中指定多个包,多个包逗号隔开。如:
<context:component-scan base-package=“cn.gacl.dao.impl,cn.gacl.service.impl,cn.gacl.action”/>
@Component@Component是所有受Spring 管理组件的通用形式,@Component注解可以放在类的头上,@Component不推荐使用。
@Controller@Controller对应表现层的Bean,也就是Action,例如:
@Controller @Scope("prototype") public class UserAction extends BaseAction<User>{ …… }使用@Controller注解标识UserAction之后,就表示要把UserAction交给Spring容器管理,在Spring容器中会存在一个名字为"userAction"的action,这个名字是根据UserAction类名来取的。注意:如果@Controller不指定其value【@Controller】,则默认的bean名字为这个类的类名首字母小写,如果指定value【@Controller(value=“UserAction”)】或者【@Controller(“UserAction”)】,则使用value作为bean的名字。 @Scope(“prototype”)表示将Action的范围声明为原型,可以利用容器的scope="prototype"来保证每一个请求有一个单独的Action来处理,避免struts中Action的线程安全问题。spring 默认scope 是单例模式(scope=“singleton”),这样只会创建一个Action对象,每次访问都是同一Action对象,数据不安全,struts2 是要求每次次访问都对应不同的Action,scope=“prototype” 可以保证当有请求的时候都创建一个Action对象。
@Service@Service对应的是业务层Bean,例如:
@Service("userService") public class UserServiceImpl implements UserService { ……… }@Service(“userService”)注解是告诉Spring,当Spring要创建UserServiceImpl的的实例时,bean的名字必须叫做"userService",这样当Action需要使用UserServiceImpl的的实例时,就可以由Spring创建好的"userService",然后注入给Action:在Action只需要声明一个名字叫"userService"的变量来接收由Spring注入的"userService"即可,具体代码如下:
// 注入userService @Resource(name = "userService") private UserService userService;注意:在Action声明的"userService"变量的类型必须是"UserServiceImpl"或者是其父类"UserService",否则由于类型不一致而无法注入,由于Action中的声明的"userService"变量使用了@Resource注解去标注,并且指明了其name = “userService”,这就等于告诉Spring,说我Action要实例化一个"userService",你Spring快点帮我实例化好,然后给我,当Spring看到userService变量上的@Resource的注解时,根据其指明的name属性可以知道,Action中需要用到一个UserServiceImpl的实例,此时Spring就会把自己创建好的名字叫做"userService"的UserServiceImpl的实例注入给Action中的"userService"变量,帮助Action完成userService的实例化,这样在Action中就不用通过"UserService userService = new UserServiceImpl();"这种最原始的方式去实例化userService了。如果没有Spring,那么当Action需要使用UserServiceImpl时,必须通过"UserService userService = new UserServiceImpl();"主动去创建实例对象,但使用了Spring之后,Action要使用UserServiceImpl时,就不用主动去创建UserServiceImpl的实例了,创建UserServiceImpl实例已经交给Spring来做了,Spring把创建好的UserServiceImpl实例给Action,Action拿到就可以直接用了。Action由原来的主动创建UserServiceImpl实例后就可以马上使用,变成了被动等待由Spring创建好UserServiceImpl实例之后再注入给Action,Action才能够使用。这说明Action对"UserServiceImpl"类的“控制权”已经被“反转”了,原来主动权在自己手上,自己要使用"UserServiceImpl"类的实例,自己主动去new一个出来马上就可以使用了,但现在自己不能主动去new "UserServiceImpl"类的实例,new "UserServiceImpl"类的实例的权力已经被Spring拿走了,只有Spring才能够new “UserServiceImpl"类的实例,而Action只能等Spring创建好"UserServiceImpl"类的实例后,再“恳求”Spring把创建好的"UserServiceImpl"类的实例给他,这样他才能够使用"UserServiceImpl”,这就是Spring核心思想“控制反转”,也叫“依赖注入”,“依赖注入”也很好理解,Action需要使用UserServiceImpl干活,那么就是对UserServiceImpl产生了依赖,Spring把Acion需要依赖的UserServiceImpl注入(也就是“给”)给Action,这就是所谓的“依赖注入”。对Action而言,Action依赖什么东西,就请求Spring注入给他,对Spring而言,Action需要什么,Spring就主动注入给他。
@ Repository@Repository对应数据访问层Bean ,例如:
@Repository(value="userDao") public class UserDaoImpl extends BaseDaoImpl<User> { ……… }@Repository(value=“userDao”)注解是告诉Spring,让Spring创建一个名字叫"userDao"的UserDaoImpl实例。
当Service需要使用Spring创建的名字叫"userDao"的UserDaoImpl实例时,就可以使用@Resource(name = “userDao”)注解告诉Spring,Spring把创建好的userDao注入给Service即可。
// 注入userDao,从数据库中根据用户Id取出指定用户时需要用到 @Resource(name = "userDao") private BaseDao<User> userDao; Spring常用注解汇总本文汇总了Spring的常用注解,以方便大家查询和使用,具体如下:
使用注解之前要开启自动扫描功能,其中base-package为需要扫描的包(含子包)。
<context:component-scan base-package=“cn.test”/> @Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。 @Scope注解 作用域 @Lazy(true) 表示延迟初始化 @Service用于标注业务层组件、 @Controller用于标注控制层组件(如struts中的action) @Repository用于标注数据访问组件,即DAO组件。 @Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。 @Scope用于指定scope作用域的(用在类上) @PostConstruct用于指定初始化方法(用在方法上) @PreDestory用于指定销毁方法(用在方法上) @DependsOn:定义Bean初始化及销毁时的顺序 @Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常 @Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下: @Autowired @Qualifier(“personDaoBean”) 存在多个实例配合使用 @Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。 @PostConstruct 初始化注解 @PreDestroy 摧毁注解 默认 单例 启动就加载 @Async异步方法调用
Spring MVC @Controller在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。在SpringMVC 中提供了一个非常简便的定义Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用@Controller 标记一个类是Controller ,然后使用@RequestMapping 和@RequestParam 等一些注解用以定义URL 请求和Controller 方法之间的映射,这样的Controller 就能被外界访问到。此外Controller 不会直接依赖于HttpServletRequest 和HttpServletResponse 等HttpServlet 对象,它们可以通过Controller 的方法参数灵活的获取到。 @Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器。单单使用@Controller 标记在一个类上还不能真正意义上的说它就是SpringMVC 的一个控制器类,因为这个时候Spring 还不认识它。那么要如何做Spring 才能认识它呢?这个时候就需要我们把这个控制器类交给Spring 来管理。有两种方式:
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。 当@RequestMapping 标记在Controller 类上的时候,里面使用@RequestMapping 标记的方法的请求地址都是相对于类上的@RequestMapping 而言的;当Controller 类上没有标记@RequestMapping 注解时,方法上的@RequestMapping 都是绝对路径。这种绝对路径和相对路径所组合成的最终路径都是相对于根路径“/ ”而言的。
使用 @RequestMapping 来映射 Request 请求与处理器 方式一:通过常见的类路径和方法路径结合访问controller方法下面例子,就是因为MyController 没有被@RequestMapping 标记,所以当需要访问到里面使用了@RequestMapping 标记的showView 方法时,就是使用的绝对路径/showView请求就可以了。
@Controller public class MyController { @RequestMapping ( "/showView" ) public ModelAndView showView() { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName( "viewName" ); modelAndView.addObject( " 需要放到 model 中的属性名称 " , " 对应的属性值,它是一个对象 " ); return modelAndView; } }在控制器上加了@RequestMapping 注解,所以当需要访问到里面使用了@RequestMapping 标记的方法showView() 的时候就需要使用showView 方法上@RequestMapping 相对于控制器MyController上@RequestMapping 的地址,即/test/showView
@Controller @RequestMapping ( "/test" ) public class MyController { @RequestMapping ( "/showView" ) public ModelAndView showView() { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName( "viewName" ); modelAndView.addObject( " 需要放到 model 中的属性名称 " , " 对应的属性值,它是一个对象 " ); return modelAndView; } } 方式二:使用uri模板URI 模板就是在URI 中给定一个变量,然后在映射的时候动态的给该变量赋值。如URI 模板localhost/app/{variable1}/index.html ,这个模板里面包含一个变量variable1 ,那么当我们请求localhost/app/hello/index.html 的时候,该URL 就跟模板相匹配,只是把模板中的variable1 用hello 来取代。这个变量在SpringMVC 中是使用@PathVariable 来标记的。在SpringMVC 中,我们可以使用@PathVariable 来标记一个Controller 的处理方法参数,表示该参数的值将使用URI 模板中对应的变量的值来赋值。
代码中我们定义了两个URI 变量,一个是控制器类上的variable1 ,一个是showView 方法上的variable2 ,然后在showView 方法的参数里面使用@PathVariable 标记使用了这两个变量。所以当我们使用/test/hello/showView/2.do 来请求的时候就可以访问到MyController 的showView 方法,这个时候variable1 就被赋予值hello ,variable2 就被赋予值2 ,然后我们在showView 方法参数里面标注了参数variable1 和variable2 是来自访问路径的path 变量,这样方法参数variable1 和variable2 就被分别赋予hello 和2 。方法参数variable1 是定义为String 类型,variable2 是定义为int 类型,像这种简单类型在进行赋值的时候Spring 是会帮我们自动转换的。
@Controller @RequestMapping ( "/test/{variable1}" ) public class MyController { @RequestMapping ( "/showView/{variable2}" ) public ModelAndView showView( @PathVariable String variable1, @PathVariable ( "variable2" ) int variable2) { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName( "viewName" ); modelAndView.addObject( " 需要放到 model 中的属性名称 " , " 对应的属性值,它是一个对象 " ); return modelAndView; } }在上面的代码中我们可以看到在标记variable1 为path 变量的时候我们使用的是@PathVariable ,而在标记variable2 的时候使用的是@PathVariable(“variable2”) 。这两者有什么区别呢?第一种情况就默认去URI 模板中找跟参数名相同的变量,但是这种情况只有在使用debug 模式进行编译的时候才可以,而第二种情况是明确规定使用的就是URI 模板中的variable2 变量。当不是使用debug 模式进行编译,或者是所需要使用的变量名跟参数名不相同的时候,就要使用第二种方式明确指出使用的是URI 模板中的哪个变量。 除了在请求路径中使用URI 模板,定义变量之外,@RequestMapping 中还支持通配符“* ”。如下面的代码我就可以使用/myTest/whatever/wildcard.do 访问到Controller 的testWildcard 方法。如:
@Controller @RequestMapping ( "/myTest" ) public class MyController { @RequestMapping ( "*/wildcard" ) public String testWildcard() { System. out .println( "wildcard------------" ); return "wildcard" ; } }当@RequestParam中没有指定参数名称时,Spring 在代码是debug 编译的情况下会默认取更方法参数同名的参数,如果不是debug 编译的就会报错。
使用 @RequestMapping 的一些高级用法RequestMapping注解有六个属性,下面我们把她分成三类进行说明
value | 指定请求的实际地址,指定的地址可以是URI Template 模式 |
method | 指定请求的method类型, GET、POST、PUT、DELETE等 |
consumes | 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html; |
produces | 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回; |
params | 指定request中必须包含某些参数值是,才让该方法处理。 |
headers | 指定request中必须包含某些指定的header值,才能让该方法处理请求。 |
用@RequestMapping 的params 属性指定了三个参数,这些参数都是针对请求参数而言的,它们分别表示参数param1 的值必须等于value1 ,参数param2 必须存在,值无所谓,参数param3 必须不存在,只有当请求/testParams.do 并且满足指定的三个参数条件的时候才能访问到该方法。所以当请求/testParams.do?param1=value1¶m2=value2 的时候能够正确访问到该testParams 方法,当请求/testParams.do?param1=value1¶m2=value2¶m3=value3 的时候就不能够正常的访问到该方法,因为在@RequestMapping 的params 参数里面指定了参数param3 是不能存在的。
method属性 @RequestMapping (value= "testMethod" , method={RequestMethod. GET , RequestMethod. DELETE }) public String testMethod() { return "method" ; }在上面的代码中就使用method 参数限制了以GET 或DELETE 方法请求/testMethod 的时候才能访问到该Controller 的testMethod 方法。
headers属性 @RequestMapping (value= "testHeaders" , headers={ "host=localhost" , "Accept" }) public String testHeaders() { return "headers" ; }headers 属性的用法和功能与params 属性相似。在上面的代码中当请求/testHeaders.do 的时候只有当请求头包含Accept 信,且请求的host 为localhost 的时候才能正确的访问到testHeaders 方法。
@RequestMapping 标记的处理器方法支持的方法参数和返回类型 支持的方法参数类型该Controller的所有方法在调用前,先执行此@ModelAttribute方法,可用于注解和方法参数中,可以把这个@ModelAttribute特性,应用在BaseController当中,所有的Controller继承BaseController,即可实现在调用Controller时,先执行@ModelAttribute方法。 @SessionAttributes即将值放到session作用域中,写在class上面。 SpringMVC 支持使用 @ModelAttribute 和 @SessionAttributes 在不同的模型(model)和控制器之间共享数据。 @ModelAttribute 主要有两种使用方式,一种是标注在方法上,一种是标注在 Controller 方法参数上。
当 @ModelAttribute 标记在方法上的时候,该方法将在处理器方法执行之前执行,然后把返回的对象存放在 session 或模型属性中,属性名称可以使用 @ModelAttribute(“attributeName”) 在标记方法的时候指定,若未指定,则使用返回类型的类名称(首字母小写)作为属性名称。关于 @ModelAttribute 标记在方法上时对应的属性是存放在 session 中还是存放在模型中,我们来做一个实验,看下面一段代码。
@Controller @RequestMapping ( "/myTest" ) public class MyController { @ModelAttribute ( "hello" ) public String getModel() { System. out .println( "-------------Hello---------" ); return "world" ; } @ModelAttribute ( "intValue" ) public int getInteger() { System. out .println( "-------------intValue---------------" ); return 10; } @RequestMapping ( "sayHello" ) public void sayHello( @ModelAttribute ( "hello" ) String hello, @ModelAttribute ( "intValue" ) int num, @ModelAttribute ( "user2" ) User user, Writer writer, HttpSession session) throws IOException { writer.write( "Hello " + hello + " , Hello " + user.getUsername() + num); writer.write( "\\r" ); Enumeration enume = session.getAttributeNames(); while (enume.hasMoreElements()) writer.write(enume.nextElement() + "\\r" ); } @ModelAttribute ( "user2" ) public User getUser(){ System. out .println( "---------getUser-------------" ); return new User(3, "user2" ); } }当我们请求 /myTest/sayHello.do 的时候使用 @ModelAttribute 标记的方法会先执行,然后把它们返回的对象存放到模型中。最终访问到 sayHello 方法的时候,使用 @ModelAttribute 标记的方法参数都能被正确的注入值。执行结果如下所示:
Hello world,Hello user210
由执行结果我们可以看出来,此时 session 中没有包含任何属性,也就是说上面的那些对象都是存放在模型属性中,而不是存放在 session 属性中。那要如何才能存放在 session 属性中呢?这个时候我们先引入一个新的概念 @SessionAttributes ,它的用法会在讲完 @ModelAttribute 之后介绍,这里我们就先拿来用一下。我们在 MyController 类上加上 @SessionAttributes 属性标记哪些是需要存放到 session 中的。看下面的代码:
@Controller @RequestMapping ( "/myTest" ) @SessionAttributes (value={ "intValue" , "stringValue" }, types={User. class }) public class MyController { @ModelAttribute ( "hello" ) public String getModel() { System. out .println( "-------------Hello---------" ); return "world" ; } @ModelAttribute ( "intValue" ) public int getInteger() { System. out .println( "-------------intValue---------------" ); return 10; } @RequestMapping ( "sayHello" ) public void sayHello(Map<String, Object> map, @ModelAttribute ( "hello" ) String hello, @ModelAttribute ( "intValue" ) int num, @ModelAttribute ( "user2" ) User user, Writer writer, HttpServletRequest request) throws IOException { map.put( "stringValue" , "String" ); writer.write( "Hello " + hello + " , Hello " + user.getUsername() + num); writer.write( "\\r" ); HttpSession session = request.getSession(); Enumeration enume = session.getAttributeNames(); while (enume.hasMoreElements()) writer.write(enume.nextElement() + "\\r" ); System. out .println(session); } @ModelAttribute ( "user2" ) public User getUser() { System. out .println( "---------getUser-------------" ); return new User(3, "user2" ); } }在上面代码中我们指定了属性为 intValue 或 stringValue 或者类型为 User 的都会放到 Session中,利用上面的代码当我们访问 /myTest/sayHello.do 的时候,结果如下:
Hello world,Hello user210
仍然没有打印出任何 session 属性,这是怎么回事呢?怎么定义了把模型中属性名为 intValue 的对象和类型为 User 的对象存到 session 中,而实际上没有加进去呢?难道我们错啦?我们当然没有错,只是在第一次访问 /myTest/sayHello.do 的时候 @SessionAttributes 定义了需要存放到 session 中的属性,而且这个模型中也有对应的属性,但是这个时候还没有加到 session 中,所以 session 中不会有任何属性,等处理器方法执行完成后 Spring 才会把模型中对应的属性添加到 session 中。所以当请求第二次的时候就会出现如下结果: Hello world,Hello user210 user2 intValue stringValue
当 @ModelAttribute 标记在处理器方法参数上的时候,表示该参数的值将从模型或者 Session 中取对应名称的属性值,该名称可以通过 @ModelAttribute(“attributeName”) 来指定,若未指定,则使用参数类型的类名称(首字母小写)作为属性名称。
@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数。如:
@Controller public class TestController { @RequestMapping(value="/user/{userId}/roles/{roleId}",method = RequestMethod.GET) public String getLogin(@PathVariable("userId") String userId, @PathVariable("roleId") String roleId){ System.out.println("User Id : " + userId); System.out.println("Role Id : " + roleId); return "hello"; } @RequestMapping(value="/product/{productId}",method = RequestMethod.GET) public String getProduct(@PathVariable("productId") String productId){ System.out.println("Product Id : " + productId); return "hello"; } @RequestMapping(value="/javabeat/{regexp1:[a-z-]+}", method = RequestMethod.GET) public String getRegExp(@PathVariable("regexp1") String regexp1){ System.out.println("URI Part 1 : " + regexp1); return "hello"; } } @requestParam@requestParam主要用于在SpringMVC后台控制层获取参数,类似一种是request.getParameter(“name”),它有三个常用参数:defaultValue = “0”, required = false, value = “isApp”;defaultValue 表示设置默认值,required 铜过boolean设置是否是必须要传入的参数,value 值表示接受的传入的参数类型。
@ResponseBody作用: 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
handler method 参数绑定常用的注解handler method 参数绑定常用的注解,我们根据他们处理的Request的不同内容部分分为四类:(主要讲解常用类型)
处理requet uri 部分(这里指uri template中variable,不含queryString部分)的注解:@PathVariable;当使用@RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvariable注解绑定它传过来的值到方法的参数上。
@Controller @RequestMapping("/owners/{ownerId}") public class RelativePathUriTemplateController { @RequestMapping("/pets/{petId}") public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // implementation omitted } }上面代码把URI template 中变量 ownerId的值和petId的值,绑定到方法的参数上。若方法参数名称和需要绑定的uri template中变量名称不一致,需要在@PathVariable(“name”)指定uri template中的名称。
处理request header部分的注解: @RequestHeader, @CookieValue;@RequestHeader 注解,可以把Request请求header部分的值绑定到方法的参数上。
这是一个Request 的header部分: Host localhost:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9 Accept-Language fr,en-gb;q=0.7,en;q=0.3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive 300 @RequestMapping("/displayHeaderInfo.do") public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding, @RequestHeader("Keep-Alive") long keepAlive) { }上面的代码,把request header部分的 Accept-Encoding的值,绑定到参数encoding上了, Keep-Alive header的值绑定到参数keepAlive上。 @CookieValue 可以把Request header中关于cookie的值绑定到方法的参数上。 例如有如下Cookie值: JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
@RequestMapping("/displayHeaderInfo.do") public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie) { }即把JSESSIONID的值绑定到参数cookie上。
处理request body部分的注解:@RequestParam, @RequestBody;@RequestParam
@RequestBody 该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等; 它是通过使用HandlerAdapter 配置的HttpMessageConverters来解析post data body,然后绑定到相应的bean上的。 因为配置有FormHttpMessageConverter,所以也可以用来处理 application/x-www-form-urlencoded的内容,处理完的结果放在一个MultiValueMap<String, String>里,这种情况在某些特殊需求下使用,详情查看FormHttpMessageConverter api; 示例代码:
@RequestMapping(value = "/something", method = RequestMethod.PUT) public void handle(@RequestBody String body, Writer writer) throws IOException { writer.write(body); } 处理attribute类型是注解: @SessionAttributes, @ModelAttribute;@SessionAttributes: 该注解用来绑定HttpSession中的attribute对象的值,便于在方法中的参数里使用。 该注解有value、types两个属性,可以通过名字和类型指定要使用的attribute 对象; 示例代码:
@Controller @RequestMapping("/editPet.do") @SessionAttributes("pet") public class EditPetForm { // ... }@ModelAttribute 该注解有两个用法,一个是用于方法上,一个是用于参数上; 用于方法上时: 通常用来在处理@RequestMapping之前,为请求绑定需要从后台查询的model; 用于参数上时: 用来通过名称对应,把相应名称的值绑定到注解的参数bean上;要绑定的值来源于:
用到方法上@ModelAttribute的示例代码:
@ModelAttribute public Account addAccount(@RequestParam String number) { return accountManager.findAccount(number); }这种方式实际的效果就是在调用@RequestMapping的方法之前,为request对象的model里put(“account”, Account)。
用在参数上的@ModelAttribute示例代码:
@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST) public String processSubmit(@ModelAttribute Pet pet) { }首先查询 @SessionAttributes有无绑定的Pet对象,若没有则查询@ModelAttribute方法层面上是否绑定了Pet对象,若没有则将URI template中的值按对应的名称绑定到Pet对象的各属性上。
< context:component-scan base-package = “” />浅析component-scan 默认扫描的注解类型是 @Component,不过,在 @Component 语义基础上细化后的 @Repository, @Service 和 @Controller 也同样可以获得 component-scan 的青睐 有了<context:component-scan>,另一个<context:annotation-config/>标签根本可以移除掉,因为已经被包含进去了 另外<context:annotation-config/>还提供了两个子标签
<context:include-filter> //指定扫描的路径
<context:exclude-filter> //排除扫描的路径
<context:component-scan>有一个use-default-filters属性,属性默认为true,表示会扫描指定包下的全部的标有@Component的类,并注册成bean.也就是@Component的子注解@Service,@Reposity等。
这种扫描的粒度有点太大,如果你只想扫描指定包下面的Controller或其他内容则设置use-default-filters属性为false,表示不再按照scan指定的包扫描,而是按照<context:include-filter>指定的包扫描,示例:
<context:component-scan base-package="com.tan" use-default-filters="false"> <context:include-filter type="regex" expression="com.tan.*"/>//注意后面要写.* </context:component-scan>当没有设置use-default-filters属性或者属性为true时,表示基于base-packge包下指定扫描的具体路径
<context:component-scan base-package="com.tan" > <context:include-filter type="regex" expression=".controller.*"/> <context:include-filter type="regex" expression=".service.*"/> <context:include-filter type="regex" expression=".dao.*"/> </context:component-scan>效果相当于:
<context:component-scan base-package="com.tan" > <context:exclude-filter type="regex" expression=".model.*"/> </context:component-scan> Spring Boot @SpringBootApplication此注解是个组合注解,包括了@SpringBootConfiguration,@EnableAutoConfiguration和@ComponentScan注解。 @SpringBootConfiguration 继承至@Configuration,对于熟悉spring的开发者而言,此标注当前类是配置类,并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到srping容器中,并且实例名就是方法名。 @EnableAutoConfiguration 这个注解就是springboot能自动进行配置的魔法所在了。主要是通过此注解,能所有符合自动配置条件的bean的定义加载到spring容器中,比如根据spring-boot-starter-web ,来判断你的项目是否需要添加了webmvc和tomcat,就会自动的帮你配置web项目中所需要的默认配置。具体的使用,会在后期自定义实现一个自动启动类时,会讲解到它的一些机制。此章节就不深入了,只需要它是这个用途即可,一般上也单独使用不要这个注解,但比如需要排除一些无需自动配置的类时,可利用exclude进行排除。 @ComponentScan 这个熟悉spring的开发者也应该熟悉,会扫描当前包及其子包下被@Component,@Controller,@Service,@Repository等注解标记的类并纳入到spring容器中进行管理。
@SpringBootConfiguration@SpringBootConfiguration继承自@Configuration,二者功能也一致,标注当前类是配置类, 并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名。
@EnableAutoConfiguration这个注解告诉Spring Boot根据添加的jar依赖猜测你想如何配置Spring。由于 spring-boot-starter-web 添加了Tomcat和Spring MVC,所以auto-configuration将假定你正在开发一个web应用并相应地对Spring进行设置。Starter POMs和Auto-Configuration:设计auto-configuration的目的是更好的使用"Starter POMs",但这两个概念没有直接的联系。你可以自由地挑选starter POMs以外的jar依赖,并且Spring Boot将仍旧尽最大努力去自动配置你的应用。
你可以通过将 @EnableAutoConfiguration 或 @SpringBootApplication 注解添加到一个 @Configuration 类上来选择自动配置。 注:你只需要添加一个 @EnableAutoConfiguration 注解。我们建议你将它添加到主 @Configuration 类上。
如果发现应用了你不想要的特定自动配置类,你可以使用 @EnableAutoConfiguration 注解的排除属性来禁用它们。
<pre name="code" class="java">import org.springframework.boot.autoconfigure.*; import org.springframework.boot.autoconfigure.jdbc.*; import org.springframework.context.annotation.*; @Configuration @EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) public class MyConfiguration { } @ComponentScan@ComponentScan会扫描指定路径下的的类,并将其加入到Ioc容器中。在springboot中,@ComponentScan默认扫描@SpringBootApplication所在类的同级目录以及它的子目录。 也可以使用@ComponentScan(basePackageClasses = com.qingtian.web.controller)来制定扫描包路径
@RestController@RestController 是Spring4之后加入的注解,原来在@Controller中返回json需要@ResponseBody来配合,如果直接用@RestController替代@Controller就不需要再配置@ResponseBody,默认返回json格式。 当你实现一个RESTful web services的时候,response将一直通过response body发送。为了简化开发,Spring 4.0提供了一个专门版本的controller。下面我们来看看@RestController实现的定义:
@Target(value=TYPE) @Retention(value=RUNTIME) @Documented @Controller @ResponseBody public @interface RestController RequestMapping简化注解@GetMapping 等同于 @RequestMapping(method = RequestMethod.GET) @PostMapping 等同于 @RequestMapping(method = RequestMethod.POST) @PutMapping 等同于 @RequestMapping(method = RequestMethod.PUT) @DeleteMapping 等同于 @RequestMapping(method = RequestMethod.DELETE) @PatchMapping 等同于 @RequestMapping(method = RequestMethod.PATCH)
@ProfilesSpring Profiles提供了一种隔离应用程序配置的方式,并让这些配置只能在特定的环境下生效。任何@Component或@Configuration都能被@Profile标记,从而限制加载它的时机。
@Configuration @Profile("production") public class ProductionConfiguration { // ... } 全局异常处理@ControllerAdvice: 包含@Component。可以被扫描到。 统一处理异常。
@ExceptionHandler(Exception.class): 用在方法上面表示遇到这个异常就执行以下方法。
本文标签: 注解常用springspringmvcSpringBoot
版权声明:本文标题:Spring SpringMVC SpringBoot 常用注解说明 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1687014933a128831.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论