转载:https://zhuanlan.zhihu.com/p/32337634

1. 概述

在 Spring 组件中使用 @Value 注解的方式,很方便的读取 properties 文件的配置值。

2.使用场景

声明的变量中使用。

public static class FieldValueTestBean {
    @Value("#{ systemProperties['user.region'] }")
    private String defaultLocale;

setter 方法中。

public static class PropertyValueTestBean {
    private String defaultLocale;
    @Value("#{ systemProperties['user.region'] }")
    public void setDefaultLocale(String defaultLocale) {
        this.defaultLocale = defaultLocale;
 
public class SimpleMovieLister {
    private MovieFinder movieFinder;
    private String defaultLocale;
    @Autowired
    public void configure(MovieFinder movieFinder,
            @Value("#{ systemProperties['user.region'] }") String defaultLocale) {
        this.movieFinder = movieFinder;
        this.defaultLocale = defaultLocale;
    // ...

构造方法。

public class MovieRecommender {
    private String defaultLocale;
    private CustomerPreferenceDao customerPreferenceDao;
    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao,
            @Value("#{systemProperties['user.country']}") String defaultLocale) {
        this.customerPreferenceDao = customerPreferenceDao;
        this.defaultLocale = defaultLocale;
    // ...

3. 字符串

字符串类型的属性设置默认值。

@Value("${some.key:my default value}")
private String stringWithDefaultValue;

some.key 没有设置值,stringWithDefaultValue 变量值将会被设置成 my default value 。

如果默认值设为空,也将会被设置成默认值。

@Value("${some.key:}")
private String stringWithBlankDefaultValue;

4. 基本类型

基本类型设置默认值。

@Value("${some.key:true}")
private boolean booleanWithDefaultValue;
@Value("${some.key:42}")
private int intWithDefaultValue;

包装类型设置默认值。

@Value("${some.key:true}")
private Boolean booleanWithDefaultValue;
@Value("${some.key:42}")
private Integer intWithDefaultValue;

5. 数组

数组的默认值可以使用逗号分割。

@Value("${some.key:one,two,three}")
private String[] stringArrayWithDefaults;
@Value("${some.key:1,2,3}")
private int[] intArrayWithDefaults;

6. SpEL

使用 Spring Expression Language (SpEL) 设置默认值。

下面的代码标示在systemProperties属性文件中,如果没有设置 some.key 的值,my default system property value 会被设置成默认值。

@Value("#{systemProperties['some.key'] ?: 'my default system property value'}")
private String spelWithDefaultValue;

上面讲解使用 Spring @Value 为属性设置默认值。在项目中,提供合理的默认值,在大多情况下不用任何配置,就能直接使用。达到零配置的效果,降低被人使用的门槛。简化新Spring应用的搭建、开发、部署过程。

8.参考链接

Using Spring @Value with Defaults

Annotation-based configuration

使用@Value注解将变量进行自动注入的时候,经常会出现的一个问题就是我们可能会由于在配置参数中忘记设置该参数造成整个项目报错,其实我们可以通过给被@Value注解作用的变量进行注入的时候如果没有找到该配置参数时设置一个默认值,相当于是一个兜底的方案: 没有默认值的用法: @Value("${spring.port}") private String port; 增加默认值的用法: @V... controller中的属性使用了@value注解,并且本人之前用的${}形式,看到别人用的#{}形式,特此记录下。2.@Value注解作用的两种方式 第一种方式@Value(“${}”): 我们读取他的 server.port 属性,springMVC的controller结构如下: 结果为 :8000 属性读取成功第二种方式 @Value(“#{}”): 修改controller,如图: 启动程序发现报错: org.springframework.expression.spel.SpelEv 自己开发一个工具类,为第三方应用提供调用接口,但是打包后测试过程中,发现了一个问题就是在用@Value获取配置文件内容的时候,无法获取我们的配置信息,也无法加载我们配置的默认值!具体配置如下: @Value("${login.url:/yuxuntoo/login}") private String loginUrl; 从上方的配置文件我们也能看出所写的注解和方式是完全没有问题的! 查看源码后的具体流程 实际上就是对类上的value后面的属性值进行解析,然后拿到解析的数据和配置文件中的数据进行对比。如果对比成功,那么则通过反射,把相关的属性进行赋值。而配置文件的数据我们在上面加载environment文件的时候,已经把内容存储了起来。 主要代码在:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean 从配置上,完全没有写错的可能,见上方的配置,所以只能从不能获取配置文件内容的几种可能着手了! 变量被static关键字所修饰 我们所需要获 声明此对象映射到数据库的数据表,通过它可以为实体指定表(talbe) @Data 注解在类上, 为类提供读写属性, 此外还提供了 equals()、hashCode()、toString() 方法 @Id & @GeneratedValue(strategy= GenerationType.IDENTITY) 自动增长,适用于支持自增字段的数据库 mapper Mapper IdListMapper 根据id操作数据库 @RequestMapping("category") Controller @RestController @Controller 处理HTTP请求 @ResponseBody 返回 json 数据 @GetMapping("list") ResponseEntity @ResponseBody可以直接返回Json结果 不仅可以返回json结果,还可以定义返回的HttpHeaders和HttpStatus service @Service 自动注册到Spring容器,不需要再在applicationContext.xml文件定义bean了 @Autowired 它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 select select * from category c where c.pid = #{pid} CollectionUtils.isnotblank 判断集合是否为空 可以利用url直接查询数据库,能否访问得到数据 没有扫描到 @MapperScan("com.leyou.item.mapper") ,目录结构关系 访问网页报错 CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. 浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是于当前页同域名的路径,这能有效的阻止跨站攻击。因此:跨域问题 是针对ajax的一种限制。 解决跨域问题的方案 CORS 规范化的跨域请求解决方案,安全可靠 什么是cors 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。 当浏览器发现发现的ajax请求是简单请求时,会在请求头中携带一个字段:Origin 如果服务器允许跨域,需要在返回的响应头中携带下面信息 Access-Control-Allow-Origin:可接受的域,是一个具体域名或者*,代表任意 Access-Control-Allow-Credentials:是否允许携带cookie,默认情况下,cors不会携带cookie,除非这个值是true 实现非常简单 gateway网关中编写一个配置类 GlobalCorsConfig 添加CORS配置信息 允许的域,不要写*,否则cookie就无法使用了 是否发送Cookie信息 允许的请求方式 允许的头信息 添加映射路径,我们拦截一切请求 返回新的CorsFilter GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源 分类不能打开,当添加后却能打开。 修改一天的BUG 最后发现是实体类里属性大小写的问题引起。 注意 Bule_bird 就必须写成 BlueBird Brand PageResult 分页结果一般至少需要两个数据 总条数 total 当前页数据 items 有些还需要总页数 总页数 totalPage Controller @RequestParam(value = "page",defaultValue = "1") Integer page GET和POST请求传的参数会自动转换赋值到@RequestParam 所注解的变量上 defaultValue 默认值 required 默认值为true , 当为false时 这个注解可以不传这个参数 null || .size()==0 ResponseEntity(HttpStatus.NOT_FOUND) 返回404没找到 ResponseEntity.ok 返回ok状态 service 通用分页拦截器 PageHelper.startPage(page,row); Example查询 Example example = new Example(Brand.class); mybatis的逆向工程中会生成实例及实例对应的example,example用于添加条件,相当where后面的部分 xxxExample example = new xxxExample(); Criteria criteria = new Example().createCriteria(); StringUtils.isNotBlank isNotBlank(str) 等价于 str != null && str.length > 0 && str.trim().length > 0 str.trim() 去掉字符串头尾的空格 报错500 com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'idASC' in 'order clause' 错误:(desc ? "DESC" : "ASC"); 正确:(desc ? " DESC" : " ASC"); 字符串空格问题 Controller (Brand brand,@RequestParam("cids") List cids) ResponseEntity new ResponseEntity(HttpStatus.CREATED); 201成功 service @Transactional 自动纳入 Spring 的事务管理 使用默认配置,抛出异常之后,事务会自动回滚,数据不会插入到数据库。 setId(null) insert(brand) 新增中间表 mapper @Insert (#{cid},#{bid}) @Param 表示给参数命名,名称就是括号中的内容 name 命名为aa,然后sql语句....where s_name= #{aa} 中就可以根据aa得到参数值 Controller @PathVariable("bid") 通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的入参中。 select * from tb_category where id in (select category_id from tb_category_brand where brand_id = #{bid}) 报错500 空指针异常 调用Service时候 忘记@Autowired VO视图对象 @NoArgsConstructor 生成一个无参数的构造方法 @AllArgsConstructor 会生成一个包含所有变量 Controller @PutMapping 添加信息,倾向于用@PostMapping,如果是更新信息,倾向于用@PutMapping。两者差别不是很明显 return ResponseEntity.ok().build(); service 根据id修改 先删除后新增 删除(前端有问题,待完善) Group 品牌分类id查询 @Transient 指定该属性或字段不是永久的。 它用于注释实体类,映射超类或可嵌入类的属性或字段。 @Column(name = "'numeric'") 用来标识实体类中属性与数据表中字段的对应关系 name 定义了被标注字段在数据库表中所对应字段的名称; mapper service Controller 报错500 实体类@table路径写错 Controller @RequestBody 常用其来处理application/json类型 子主题 2 将请求体中的JSON字符串绑定到相应的bean上 Controller @PutMapping service updateByPrimaryKey Controller @DeleteMapping @PathVariable Param 规格组id查询规格 url:params?gid=14 @GetMapping("params") Controller @RequestParam @PostMapping("param") @RequestBody ResponseEntity.status(HttpStatus.CREATED).build(); @RequestBody @PathVariable 分支主题 3 遇到的问题 pom.xml 文件未下载完整,删掉后重新下载 能存在重复文件,IDEA不能确定文件路径,需要搜索删掉多余的 Param 小问题:数据库删除后页面没有立即显示 Brand 删除(前端有问题,待完善) 环境:nacos 1.4.0,xxl-job 2.0.0 ,springbootnacos升级到1.4.0之后远程配置值为空时,启动报错远程配置xxx.yamlxxl:job:admin:addresses=: http://xxx.xxx/xxl-job-adminexecutor:appname: job-serviceaddress=:ip=:port: 5017错误Caused by: j... @Value的值有两类: 1、${ property : default_value } 2、#{ obj.property? :default_value }第一个注入的是外部配置文件对应的property,第二个则是SpEL表达式对应的内容。 default_value是前面的值为空时的默认值。注意二者的不同,#{}里面那个obj代表对象。第一种方式:${}1、新建properti... SpringBoot配置文件类型 SpringBoot配置文件类型和作用: SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用 application.properties或者application.yml(application.yaml)进行配置 SpringBoot默认会从Resources目录下加载application.properties或application.yml(application.yaml)文件 yml配置文件的语法 配置普通数据:语法:key:valuevalue之前有个空格) #普通数据的配置 name: -Dapollo.meta=http://192.168.0.194:8080 -Denv=dev -Didc=qqq -Dcmdb.isCMDB.cmdbFlag=Y 初始化ApolloConfigChangeListener注解中value属性的默认值,如果不配置,默认为application,需要加入使用了 @appmodule注解的namespace,当然这只需要扫描配置包(basePackage)下的 spring.xml <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <description>Spring公共配置文件</description> <!-- 启用spring注解支持 --> <context:annotation-config /> <!-- <bean id="sessionFactory"--> <!-- class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">--> <!-- <property name="configLocation"--> <!-- value="classpath:hibernate.cfg.xml">--> <!-- </property>--> <!-- </bean>--> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <value>classpath*:jdbc.properties</value> </list> </property> </bean> <!-- 数据源配置,主要用于开发测试环境 --> <!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <!-- 连接池启动时的初始值 --> <property name="initialSize" value="${jdbc.initialSize}"/> <!-- 连接池的最大值 --> <property name="maxActive" value="${jdbc.maxActive}"/> <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 --> <property name="maxIdle" value="${jdbc.maxIdle}"/> <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 --> <property name="minIdle" value="${jdbc.minIdle}"/> </bean> <!-- 数据源配置,在生产环境使用应用服务器的数据库连接池 --> <!-- <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/store" />--> <!--Hibernate配置--> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"><!--此处hibernate 的映射采用的是.xml 配置则应设置为:class=”org.springframework.orm.hibernate3.LocalSessionFactoryBean”--> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="default_schema">${jdbc.username}</prop> </props> </property> <property name="annotatedClasses"> <!-- 此处hibernate 的映射采用的是.xml 配置同则应设置name=”mappingResource”--> <value>com.sbz.application.catering.entity.user.UserRegister</value><!-- 此处hibernate 的映射 采用的是.xml 配置同则应设置<value>具体配置文件名(*.hbm.xml)</value>--> </list> </property> </bean> <!-- 事务配置管理 --> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- JTA环境的事务配置 <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager or WebLogicJtaTransactionManager"/> --> <!-- 使用annotation定义事务 --> <tx:annotation-driven transaction-manager="transactionManager" /> <!-- 保证POJO中标注@Required的属性被注入 --> <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" /> <!-- 使用 annotation 自动注册bean,并检查@Controller, @Service, @Repository注解已被注入,也可以分开注释,或者固定某个目录下 --> <context:component-scan base-package="*" /> <!-- <aop:config>--> <!-- execution第一个星号代表任何返回类型,第二个星号代表com.sbz.service下的所有包,第三个星号代表所有方法,括号中的两个点代表任何参数--> <!-- <aop:pointcut id="myPointcut" expression="execution(public * com.sbz.*.service.*.*(..))"/>--> <!-- <aop:advisor advice-ref="myAdvice" pointcut-ref="myPointcut"/>--> <!-- </aop:config>--> <!--AOP代表的意思: // 所有符合pointcut条件的类或方法,都执行myAdvice建议,advice里定义了,所有的save方法,find方法都要执行transactionManager这个切面。 // 并且save方法的事物是必须的,find方法是只读的。 </beans> --------------------------------------------------------------------------- struts.xml <!--下述语句是将struts2交给spring管理 --> <constant name="struts.objectFactory" value="spring" /> <!-- 更改struts2请求Action的后缀名,默认为action。若想去掉后缀,设为","即可 --> <constant name="struts.action.extension" value=","/> <!-- 当配置文件修改后,系统自动加载该文件。开发阶段建议打开此功能 --> <constant name="struts.counfiguraction.xml.reload" value="true"/> <!-- 指定浏览器输出的编码格式 --> <constant name="struts.il8n.encoding" value="utf-8"/> <!--将action内容放在package元素下,package元素的name值与extends值可以使用默认值,如下所示 --> <package name="abstract_struts" abstract="true" extends="struts-default" namespace="/"> <interceptors> <interceptor name="authority" class="com.sbz.application.common.LoginIntercepter" /> <interceptor-stack name="loginStack"> <interceptor-ref name="authority" /> <interceptor-ref name="defaultStack" /> </interceptor-stack> </interceptors> <!-- <default-interceptor-ref name="loginStack" /> --> <global-results> <!-- 下面定义的结果对所有的Action都有效 --> <result name="exception">/common/exception.jsp</result> <result name="fail">/common/exception.jsp</result> <result name="input">/common/exception.jsp</result> <result name="success">/common/success.jsp</result> <result name="login">/index.jsp</result> </global-results> <global-exception-mappings> <!-- 指Action抛出Exception异常时,转入名为exception的结果。 --> <exception-mapping exception="java.lang.Exception" result="exception"/> </global-exception-mappings> </package> <!-- 包含的配置文件 --> <include file="/resource/struts-user.xml"></include>