参考文章

注解位置

  • 注解可以放在方法头上,也可以放在方法限定符后面

    @RequestMapping(value="/testuploadimg", method = RequestMethod.POST)
    public @ResponseBody String uploadImg() {}
    

    @ReponseBody

  • 返回json字符串或json对象。
  • 在SpringMvc中当返回值是String时,如果不加此注解则Spring就会找这个String对应的页面,找不到则报404错误。
  • 如果加上的话@ResponseBody就会把返回值放到response对象中

    @RequestBody

  • 提取json形式的入参中的属性绑定到同名属性上。
  • 例如:

    $.ajax({
        url:"/login",
        type:"POST",
        data:'{"userName":"admin","pwd","admin123"}',
        content-type:"application/json charset=utf-8",
        success:function(data){
            alert("request success ! ");
        }
    });
    
    @requestMapping("/login")
    public void login(@requestBody String userName,@requestBody String pwd){
        System.out.println(userName+" :"+pwd);
    }
    
  • 以上情况是将json中的两个变量赋给了同名的字符串,假如有一个User类,拥有userName和pwd两个属性,则上述参数形式可以改为:@RequestBody User user。
  • @RequestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容,比如说:application/json或者是application/xml等。一般情况下来说常用其来处理application/json类型。
  • 在一些特殊情况下@RequestBody也可以用来处理content-type类型为application/x-www-form-urlcoded的内容,比如jQuery easyUI的datagrid请求数据的时候、小型项目值创建一个pojo类的话也可以。

@Autowired

加在属性上
  • 自动注入bean
  • 在声明变量语句前加上该注释,即完成了免new直接实例化(免new的意思是前面已通过@Configuration(+@Bean)或者@Component注册好bean了)

    @Autowired
    private Car BMW;
    
  • 默认先byType,找Car类的bean,如果找到多个bean,则按照byName方法比对找名为BMW的bean,如果还有多个,则抛出异常。
  • 使用@Qualifier才可以手动指定先byName方式注入,由于Spring搞成的bean默认都是类名小写,所以一般这里的值都是类名小写。

//通过此注解完成查找满足Fruit的bean,然后找到指定的pear
@Autowired
@Qualifier("pear") 
public Fruit fruit;
  • 如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false)。这样找不到bean时不会报错而是赋予null。
  • 默认单例模式,在不同的类里用此注解注入的同类的bean都是同一个。
  • required属性:默认required=true,若设为false则表示被注解的属性即使找不到对应的bean来装配也没事,不用报错,程序照常执行。
加在方法上
  • 同样也是注入bean,加载方法上则方法会被自动调用,方法参数则被自动装配

    public class TextEditor {
       //一个自定义的类    
       private SpellChecker spellChecker;
    
       @Autowired //自动装配,这个方法被自动调用
       public void setSpellChecker(SpellChecker spellChecker){ //被调用后实例化一个SpellChecker
          this.spellChecker = spellChecker; //赋予类属性
       }
    
       //直接调用这个方法,其中spellChecker由于上面setSpellChecker被自动调用所以已经实例化了
       public void spellCheck() {
          spellChecker.checkSpelling();
       }
    }
    

@Resource

  • 和@Autowired相似,只是默认装配优先规则不同,并且@Resource是J2EE的注解,是Java自己的东西。因此建议使用@Resource,以减少代码和Spring之间的耦合。
  • 默认byName自动注入(用byName会快一点),如果找不到再byType,再找不到则抛异常,无论按那种方式如果找到多个则抛异常。
  • 可以手动指定bean,它有2个属性分别是name和type,使用name属性,@Resource(name=”bean名字”),则使用byName的自动注入,从上下文查找名称(id)匹配的bean注入;而使用type属性,@Resource(type=”bean的class”)则使用byType自动注入。
  • 不能用于注入静态属性

    public class Zoo
    {
        @Resource(name = "tiger")
        private Tiger tiger;
    
        @Resource(type = Monkey.class)
        private Monkey monkey;
    
        public String toString()
        {
            return tiger + "\n" + monkey;
        }
    }
    
  • 默认单例模式,在不同的类里用此注解注入的同类的bean都是同一个。
  • 在service层我们经常定义接口,然后写实现类,然后搞成bean的是实现类,但是我们用本注解引入这个bean时,只能将类型声明为接口,而不能是实现类:

    @Resource
    private UserService userService; //不能是UserServiceImpl
    
  • 否则报错:Can not set field to $Proxy;不知道@Autowired是不是这样的。
  • 一定要用实现类的话可以在配置文件加入:

    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> 
    <!--或者--> 
    <aop:config proxy-target-class="true">
    

@SpringBootApplication

  • 包含下面三个注解

@Configuration

  • 定义配置类,可替换xml配置文件,被注解的类内包含被@Bean注解的方法,这些方法即注册了bean。
@Configuration
public class MockConfuration{
    属性
    方法
}
  • 以上代码相当于把该类作为spring的xml配置文件中的(默认单例),作用为配置spring容器(上下文)
  • 被注解的类不可以是final类型,不可以是匿名类,嵌套的@Configuration必须是静态类。
  • 类中任何一个标注了@Bean的方法,其返回值将作为一个bean注册到spring的IOC容器,方法名则为其实例化对象
@Configuration
public class MockConfuguration{
    @Bean(name="...") //指定bean名称默认为方法名
    public MockService mockService(){//假定MockService是一个接口
        return new MockServiceImpl();//MockServiceImpl是其实现类,它未加任何注解
    }
}
  • 相当于xml中的,作用为注册bean对象。

  • @Bean相当于下面配置

  • 在类内立即使用这个bean
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    /**
    * 注册bean
    */
    @Bean
    private UserDetailsService loginService() {
        return new LoginServiceImpl();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(loginService());//执行这个方法,注册bean后作为方法参数使用
    }
}
  • 表达bean与bean之间的依赖关系

  • @Bean不能单独使用,应搭配@Configuration、@Component、@Controller、@Service、@Ripository使用。
  • SpringBoot项目的config包就经常用这种方式来注册bean。
  • 也可以用@Configuration+@Component来注册bean
/*bean类*/
@Component //添加注册bean的注解
public class TestBean {
}

/*配置类*/
@Configuration 
@ComponentScan(basePackages = "com.dxz.demo.configuration") //自动扫描TestBean包路径搞成bean
public class TestConfiguration {

}
  • 因为扫描的话会把整个包的类都搞成bean,所以只想把一个搞成bean的话,可以直接用第一种方法,或者只在那个类上加@Component、@Controller、@Service、@Ripository注解;如果确实都要搞成bean那肯定是第二种方法更适合。

  • spring4.0之二:@Configuration的使用:详细介绍了bean的注册原理与多种方式。

@ComponentScan

  • @ComponentScan(“包路径”):等价于<context:component-scan base-package=”com.dxz.demo”/>,扫描指定包下的所有类,发现带@Controller,@Service,@Repository,@Component注解的都会搞成bean,如果这些注解都没有指定bean名的话默认用类名首字母小写。默认扫描和被注解类所在包及all子包。
  • springboot工程启动时,由于入口类有这个注解,所以会默认加载和入口类所在目录及子目录下的所有类,所以一般情况下这些类都不用再加@ComponentScan。
  • spring的话一般会写一个配置类加上该注解,负责扫描工程所有的bean,或者在配置文件指定扫描路径
  • 写一个类
package com.study.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration //必须与此连用
@ComponentScan(basePackages={"com.study"},
    excludeFilters={@Filter(type=FilterType.ANNOTATION,
        value=EnableWebMvc.class)})
public class RootConfig {

}
  • 然后不知道是不是要在bean那边new一下这个类
  • 参考文章

@EnableAutoConfiguration

  • 像一只八爪鱼一样搜集所有的@Configuration配置,加载到springboot的IOC容器中

@Component

  • 一种通用名称,泛指可以通过spring来管理的组件。加在类上以被扫描到并搞成bean,默认直接类名小写
  • @Controller,@Service,@Repository则是一种特定的组件,通常用来表示某种场合下的组件。比如@Repository用来表示仓库(数据层,dao);@Service则用来表示服务层相关的类;@Controller则用来表示展示层(控制层)的类;不是前三种一般就用@Component了。
  • 注解在类上之后通过配置文件制定路径来扫描(或者写个能扫描的java类)并搞成bean;如果最后还是被配置文件中的bean节点依赖的话,那么也可以不用注解

    <!-- 自定义拦截器 -->
    <beans:bean id="securityInterceptor" 
        class="com.ultrapower.me.util.security.interceptor.SecurityInterceptor"> 
        <beans:property name="securityMetadataSource" ref="secureResourceFilterInvocationDefinitionSource" />
    </beans:bean>
    <!-- 获取访问url对应的所有权限 -->
    <beans:bean id="secureResourceFilterInvocationDefinitionSource" 
        class="com.ultrapower.me.util.security.interceptor.SecureResourceFilterInvocationDefinitionSource" /> //配置class属性,那么会自动到该路径去扫描并搞成bean
    
  • @Service(“name”):指定搞成的bean名

    @PostConstruct和@PreDestroy

  • 实现初始化和销毁之前进行的操作。分别只能注释一个方法,且该方法不能有参数,返回值必须是void,方法不能是静态的。

    @Primary

  • 自动装配当出现多个bean候选者时,被注解的将作为首选者,无注解将抛出异常

@Named

  • @Named和Spring的@Component功能相同。@Named可以有值,如果没有值生成的Bean名称默认和类名相同。

    @Named 
    public class Person;
    //或
    @Named("cc")
    public class Person;
    

    @RequestParam

  • 接收请求中的参数

    //将请求中参数为number映射到方法的number上,required=false表示该参数不是必需的,请求上可带可不带;若为必需,则请求中没有相应参数会导致404错误;defaultValue:默认值,表示如果哦请求中没有同名参数时的默认值          
    @RequestParam(value="number",required=false,defaultValue="0")
    String number;
    
  • 其实不写也是接收得到的,只是有时候作为一个标志或者需要它的某些属性
  • 如果参数是int类型并且required=false的话,建议以Integer变量接收,因为这时如果不传参数值会把null赋值给int,会报错。

@PathVariable

  • 将@RequestMapping指定的请求所带的参数映射到方法的参数上
@RequestMapping("/zyh/{type}")
//传入参数type,其值来自/zyh/{type}请求所带的名为type的参数,其实括号中不写也行
public String zyh(@PathVariable(value="type") int type)  {  

}
  • 和@RequestParam类似

@ResponseBody

  • 自动把被注解的类中的方法的返回值中的java对象(Map或JSONObject等)转为json串,前台才能解析
  • 可标注在方法上面或方法返回值类型前面
  • 相当于ajax请求,不用指明返回哪个页面,会自动从来的地方回去

@RequestBody

  • 将前台传来的json串转为java对象,后台才能处理。
  • 前台传参格式有两种,一种是跟在url后面的键值对,一种是json串。

@Param

  • 给参数命名

    @Query("from User u where u.name=:username")
    User findUser(@Param("username") String name1);
    //给name1命名为username,使入参被u.name=:username识别
    //@Param中的值必须和冒号后一样,至于形参和实参叫做什么就不重要了
    

    @ConfigurationProperties

  • 可以把配置文件中指定前缀的变量全部封装到类的实例中
  • 要配合@Component使用,因为不需保证注释的类能被Spring扫描到,不然Spring扫描到此注解也不知道装配到哪个类里去
  • 使用方式有两种
  • 第一种:加在类上

    @Component
    @ConfigurationProperties(prefix = "com.example.demo")
    public class People {
    
        private String name;
    
        private Integer age;
    
        private List<String> address;
    
        private Phone phone; //只有一个String类的number属性
    }
    
  • application.properties中的变量

    com.example.demo.name=${aaa:hi}
    com.example.demo.age=11
    com.example.demo.address[0]=北京
    com.example.demo.address[1]=上海
    com.example.demo.address[2]=广州
    com.example.demo.phone.number=1111111
    
  • 大功告成,实例化

    @Resource
    private People people;
    
  • 第二种:通过@Bean的方式声明,这里我们加在入口类即可
@SpringBootApplication
public class DemoApplication {

    @Bean
    @ConfigurationProperties(prefix = "com.example.demo")
    public People people() {

        return new People();
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}
  • 大功告成,实例化

    @Resource
    private People people;
    
  • PS:如果发现@ConfigurationPropertie不生效,有可能是项目的目录结构问题,你可以通过@EnableConfigurationProperties(People.class)来明确指定需要用哪个实体类来装载配置信息。

@RequestMapping

  • @RequestMapping(value=”/produces”,produces=”application/json”):表示注解方法将返回json格式的数据,此时若请求头中的Accept为application/json则可匹配。
@RequestMapping(value="/queryLearnList",method=RequestMethod.POST,
    produces = "application/json;charset=utf-8")
//produces:指定返回值类型和字符集,不过使用了@ResponseBody的话就不用指定返回值了
  • 支持通配符和ant风格的路径:
@RequestMapping(value = { "", "/page", "page*", "view/*,**/msg" })
  • 匹配url如下:

    • localhost:8080/home
    • localhost:8080/home/
    • localhost:8080/home/page
    • localhost:8080/home/pageabc
    • localhost:8080/home/view/
    • localhost:8080/home/view/view
  • 配合属性headers=”Accept=application/json”更能表明你的目的。

  • value值可以是含有变量或正则表达式的一类值
@RequestMapping("/preUpdate/{id}") //请求方式:/preUpdate/1
@RequestMapping(
    "/spring-web/{symbolicName:[a-z-]+}-{version:\d\.\d\.\d}.{extension:\.[a-z]}"
)
  • method属性默认为无,也就是什么类型的HTTP请求都可以映射。

@PostConstruct

  • Java EE 5引入的注解,Spring允许开发者在受管Bean中使用它。当DI容器实例化当前受管Bean时,@PostConstruct注解的方法会被自动触发,从而完成一些初始化工作。

    @Component
    public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    
        @Resource
        private ResourcesDao resourcesDao;
    
        private static Map<String, Collection<ConfigAttribute>> resourceMap = null;
    
        public Collection<ConfigAttribute> getAllConfigAttributes() {
            return null;
        }
    
        public boolean supports(Class<?> clazz) {
            return true;
        }
    
        /**
         * @PostConstruct是Java EE 5引入的注解,
         * Spring允许开发者在受管Bean中使用它。当DI容器实例化当前受管Bean时,
         * @PostConstruct注解的方法会被自动触发,从而完成一些初始化工作
         */
        @PostConstruct
        private void loadResourceDefine() { //加载所有资源与权限的关系
            if (resourceMap == null) {
                resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
                List<Resources> list = resourcesDao.queryAll(new Resources());
                for (Resources resources : list) {
                    Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
                    // 通过资源名称来表示具体的权限 注意:必须"ROLE_"开头
                    ConfigAttribute configAttribute = new SecurityConfig("ROLE_" + resources.getResKey());
                    configAttributes.add(configAttribute);
                    resourceMap.put(resources.getResUrl(), configAttributes);
                }
            }
        }
    
        //返回所请求资源所需要的权限
        public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
            String requestUrl = ((FilterInvocation) object).getRequestUrl();
        //  System.out.println("requestUrl is " + requestUrl);
            if(resourceMap == null) {
                loadResourceDefine();
            }
            //System.err.println("resourceMap.get(requestUrl); "+resourceMap.get(requestUrl));
            if(requestUrl.indexOf("?")>-1){
                requestUrl=requestUrl.substring(0,requestUrl.indexOf("?"));
            }
            Collection<ConfigAttribute> configAttributes = resourceMap.get(requestUrl);
            return configAttributes;
        }
    
    }
    
  • 参考文章

@PropertySource、@Value

  • @PropertySource({“classpath:jdbc.properties”}):注解在类头上,加载资源文件
  • 然后在类内属性头上
/*
 * 绑定资源属性
 */
@Value("${jdbc.driver}")
private String driverClass="hhh"; //无论此处赋值为何,都会被@Value覆盖

//设置默认值
@Value("${some.key:my default value}") //默认值也可设为空:${some.key:}
private String stringWithDefaultValue;

//数组的默认值用逗号分隔
@Value("${some.key:1,2,3}")
private int[] intArrayWithDefaults;
  • 不过有一个例子,它没有指定配置文件,直接注入,好像也可以,代码:ideaProjects/shiro-chapter16/service/impl/PasswordHelper、resources/spring-config.xml。

@RestController

  • 相当于@ResponseBody+@Controller合在一起,规定类中所有方法返回值被转换为json字符串传回前端

@ModelAttribute

  1. 作用在参数上,将客户端请求中的参数按名称注入到指定对象中,并将此对象作为传送数据存入ModelMap,便于在前端页面取用。
public String test1(@ModelAttribute("user") User user){}
  • 将user以“user”为名绑定到模型对象的属性中,若请求参数为?username=zhang&password=123&workInfo.city=bj,则User类应包含username、password和workInfo属性的city属性,那么这三个参数将被注入到“user”attribute对应的属性中,并且以“user”命名被存入模型对象汇总,在前端页面可通过${user.username}来获取username属性。
  1. 运用在方法上,会在每一个@RequestMapping注解的方法前执行,若有返回值,则自动将其存入ModelMap。
/**
 * 设置这个注解之后可以直接在前端页面使用hb这个对象(List)集合
 */
@ModelAttribute("hb") //此方法在@RequestMapping方法之前执行,并将返回值存入模型对象
public List<String> hobbiesList(){
    List<String> hobbise = new LinkedList<String>();
    hobbise.add("basketball");
    hobbise.add("football");
    hobbise.add("tennis");
    return hobbise;
}

/**
 * 前端使用hb
 */
<c:forEach items="${hb}" var="hobby" varStatus="vs">
    <c:choose>
        <c:when test="${hobby == 'basketball'}">
        篮球<input type="checkbox" name="hobbies" value="basketball">
        </c:when>

        ...

    </c:choose>
</c:forEach>
  • 若@ModelAttribute不指定属性名称则默认为返回类型的首字符小写,如返回类型为Account,则属性名为account。

  • 若@ModelAttribute和@RequestMapping同时注释一个方法,则此时返回值并不表示一个视图的名称,而是model属性的值,视图名称则由RequestToViewNameTranslator根据请求“/helloWorld.do”转换为视图HelloWorld。

@Controller 
public class HelloWorldController { 
    @RequestMapping(value = "/helloWorld.do") 
    @ModelAttribute("attributeName") 
    public String helloWorld() { 
         return "hi"; 
      } 
  }