由于早年在管理领域耕耘了一段时间,完美错过了Spring的活跃期,
多少对这个经典的技术带有一种遗憾的心态在里面的,
从下面的我的生涯手绘图中大概可以看出来我的经历。
最近由于新介入到了工业数字化领域,工作也专注于业务应用,
不怎么搞平台了,平台更多的是采取与友商战略合作的方式,
也有机会重新认识并学习一下这个被完美错过的经典技术。
以下是本次的随记。
一、本次的代码地址
https://github.com/quchunhui/demo-macket/tree/master/springboot
二、一个简单的需求场景
1) 从云平台按照一定频率拉取数据(每次间隔5秒)。
2) 将待获取的数据保存至本地数据库(MySQL)。
3)提供可视化web页面供查看流转数据状态。
4) 由DView工业软件从数据库中拉取数据(每次间隔5秒)。
5) 按照一定数量间隔向PLC下发加工数据(每次5个)。
其中,红色字体部分,为本次随记的范围。
三、学习书籍
我本在在正式开始学习及开发之前,通过书籍和付费视频对Spring boot进行了简单扫盲
学习的书籍为:《Spring 5企业级开发实战》
学习的收费视频为:极客时间《Spring全家桶》
书籍可以采用快速阅读的方式进行框架性学习
视频可以采用2倍速,按照需要先挑选部分模块学习
四、学习笔记
===初始化工程===
可以通过这个地址初始化工程
也可以通过IDEA的Spring initializr来进行初始设计。
可以选择一下组件:
Developer Tools
→Lombok
→Spring Configuration Processor
Web
→Spring Web
SQL
→Spring Boot JPA
→MySQL Driver
Ops
→Spring Boot Actuator
===spring boot actuator===
用于健康检查的模块,可以考虑引入进来。
===lombok===
Lombok想要解决了的是在我们实体Bean中大量的Getter/Setter方法,以及toString,hashCode等可能不会用到,
在使用Lombok之后,将由其来自动帮你实现代码生成,注意,其是 在运行过程中,帮你自动生成的 。就是说,将极大减少你的代码总量。
===JDBC与JPA区别===
1.定义
JDBC提供一种接口,它是由各种数据库厂商提供类和接口组成的数据库驱动,为多种数据库提供统一访问。我们使用数据库时只需要调用JDBC接口就行了。
JDBC的用途:与数据库建立连接、发送操作数据库的语句并处理结果。
JPA是Java持久层API。它是对java应用程序访问ORM(对象关系映射)框架的规范。为了我们能用相同的方法使用各种ORM框架。
JPA用途:简化现有Java EE和Java SE应用开发工作;整合ORM技术。
2.不同点:
1)使用的sql语言不同:
JDBC使用的是基于关系型数据库的标准SQL语言;
JPA通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。
2)操作的对象不同:
JDBC操作的是数据,将数据通过SQL语句直接传送到数据库中执行:
JPA操作的是持久化对象,由底层持久化对象的数据更新到数据库中。
3)数据状态不同:
JDBC操作的数据是“瞬时”的,变量的值无法与数据库中的值保持一致;
JPA操作的数据时可持久的,即持久化对象的数据属性的值是可以跟数据库中的值保持一致的。
===mvn package报错===
错误日志
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
问题原因:
Mybatis没有找到合适的加载类,其实是大部分spring - datasource - url没有加载成功,
解决办法:
在application.propertier中增加如下代码之后,编译通过。
spring.datasource.url=jdbc:mysql://localhost:3306/read_data?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username: root
spring.datasource.password: 123456
spring.datasource.driver-class-name: com.mysql.jdbc.Driver
参考博客:
https://www.cnblogs.com/wuxiang12580/archive/2019/01/25/10319914.html
===运行报错===
错误日志
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
问题原因:
数据库连接相关的配置不正确,连接不上数据库
解决办法:
application.propertier中的数据库连接信息修改为正确的即可。修改后如下:
spring.datasource.url=jdbc:mysql://localhost:3306/visual?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username: root
spring.datasource.password: 123456
spring.datasource.driver-class-name: com.mysql.jdbc.Driver
===@Builder注解===
在出现lombok之后,对象的创建工作更提供Builder方法,
它提供在设计数据实体时,对外保持private setter,而对属性的赋值采用Builder的方式,
这种方式最优雅,也更符合封装的原则,不对外公开属性的写操作!
@Builder声明实体,表示可以进行Builder方式初始化,
@Value注解,表示只公开getter,对所有属性的setter都封闭,即private修饰,所以它不能和@Builder一起使用
参考博客:
https://www.cnblogs.com/lori/p/9024933.html
===Builder注解没有builder方法===
解决办法:
在IDEA中下载lombok插件解决。vscode一样。
参考博客:
https://blog.csdn.net/Butterfly_resting/article/details/101377756
===Lombok中的@Data注解===
@Data:该注解相当于同时加上以下注解@Setter @Getter,@ToString,@EqualsAndHashCode
@Getter:生成getter方法
@Setter:生成setter方法
@AllArgsConstructor:全参构造
@NoArgsContructor:无参构造
===JdbcTemplate与NamedParameterJdbcTemplate===
SimpleJdbcTemplate加入了Java5的特性支持,例如可变参数、自动拆包封包、泛型等支持。
JdbcTemplate,已经基本能看到相对于JDBC比较强大的能力,
但是它有一个问题很不方便,就是使用参数的占位符时,必须得按照顺序来写参数,如果顺序不对,则操作失败,
NamedParameterJdbcTemplate可以用来解决这个问题,它提供了一个方式,可以通过参数名来映射参数而不是传统的"?"
可以使用SqlParameterSourceUtils.createBatch()方法,将list里的东西变成一个batch的值
List<Foo> list = new ArrayList<>();
list.add(Foo.builder().id(100L).bar("b-100").build());
list.add(Foo.builder().id(101L).bar("b-101").build());
namedParameterJdbcTemplate.batchUpdate("INSERT INTO FOO (ID, BAR) VALUES (:id, :bar)",
SqlParameterSourceUtils.createBatch(list));
===spring boot的定时任务(Scheduled)===
@Scheduled中的参数说明
@Scheduled(fixedRate=2000):上一次开始执行时间点后2秒再次执行;
Scheduled(fixedDelay=2000):上一次执行完毕时间点后2秒再次执行;
@Scheduled(initialDelay=1000, fixedDelay=2000):第一次延迟1秒执行,然后在上一次执行完毕时间点后2秒再次执行;
@Scheduled(cron="* * * * * ?"):按cron规则执行。
参考博客:
https://www.cnblogs.com/mmzs/p/10161936.html
===Spring boot Scheduled没有被定时执行===
解决办法:
@ComponentScan(basePackages = {"com.xxx"})
这是spring扫描路径,Test 是否在 com.xxx 包下面
@ComponentScan做的事情就是告诉Spring从哪里找到bean
@Component 和 @ComponentScan的使用目的不一样
@Component注解,表明当需要创建类时,这个被注解的类是一个候选类。就像是举手。
@ComponentScan 用于扫描指定包下的类。就像看都有哪些举手了
参考博客:
https://blog.csdn.net/Lamb_IT/article/details/80918704
===JPA的一些注解===
主体
@Entity
@MappedSuperclass
@Table(name)
主键
@Id
@GeneratedValue(strategy, generator)
@SuquenceGenerator(name, sequenceName)
@GeneratedValue注解的strategy属性提供四种值:
-AUTO主键由程序控制, 是默认选项 ,不设置就是这个
-IDENTITY 主键由数据库生成, 采用数据库自增长, Oracle不支持这种方式
-SEQUENCE 通过数据库的序列产生主键, MYSQL 不支持
-Table 提供特定的数据库产生主键, 该方式更有利于数据库的移植
映射
@Column(name, nullable, length, insertable, updatable)
@JoinTable(name)
@JoinColumn(name)
关系
@OneToOne
@OneToMany
@ManyToOne
@ManyToMany
@OrderBy
===几种注解的关系===
@Repository、@Service、@Controller 和 @Component 将类标识为Bean
@Repository注解便属于最先引入的一批,它用于将数据访问层 (DAO 层 ) 的类标识为 Spring Bean
@Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次。
@Service 通常作用在业务层,但是目前该功能与 @Component 相同。
@Constroller 通常作用在控制层,但是目前该功能与 @Component 相同。
通过在类上使用 @Repository、@Component、@Service 和 @Constroller 注解,
Spring会自动创建相应的 BeanDefinition 对象,并注册到 ApplicationContext 中。
这些类就成了Spring受管组件。
这三个注解除了作用于不同软件层次的类,其使用方式与 @Repository 是完全相同的。
===@GeneratedValue===
在JPA中
@GeneratedValue注解存在的意义主要就是为一个实体生成一个唯一标识的主键(JPA要求每一个实体Entity,必须有且只有一个主键)
@GeneratedValue提供了主键的生成策略。
@GeneratedValue注解有两个属性,分别是strategy和generator
generator属性的值是一个字符串,默认为"",其声明了主键生成器的名称(对应于同名的主键生成器@SequenceGenerator和@TableGenerator)
PA为开发人员提供了四种主键生成策略,其被定义在枚举类GenerationType中,包括
GenerationType.TABLE:
GenerationType.SEQUENCE:
GenerationType.IDENTITY:
GenerationType.AUTO:
参考博客:
https://blog.csdn.net/u012493207/article/details/50846616
===@Id 和 @GeneratedValue 注解===
@Id 标注用于声明一个实体类的属性映射为数据库的主键列。
该属性通常置于属性声明语句之前,可与声明语句同行,也可写在单独行上。
参考博客:
https://blog.csdn.net/Jae_Wang/article/details/80533137
===@Query===
@Query(value=" 这里就是查询语句")
@Query支持hql和原生sql两种方式,默认是hql,hql就是语句中用的是实体名字和实体属性,原生sql用的表名字和表字段,
hql方式不支持select * 要想查询全部字段可以用select 实体名 这里省略了value,参数使用了占位置符 ?1代表第一个参数?2代表第二个
@Param 代替参数占位符,hql或者sql里就用:firstname替换方法里的参数顺序可以打乱
如果是更新或者删除操作,方法上面要加@Modifying默认开启的事务只是可读的,更新操作加入@Modifying就会关闭可读
原生sql方式 不能和Pageable pageable 同时使用,要用自己的limit实现分页,原生的方式就和sql语法完全一样,使用的表名字,表字段
@Data 属于lombok注解,与jpa无关,自动生成getter/setter/equals/hashcode/tostring等方法
@Entity, @Table jpa注解,表示这个类与db的表关联,具体匹配的是表 money
@Id @GeneratedValue 作用与自增主键
@Column表明这个属性与表中的某列对应
@CreateDate根据当前时间来生成默认的时间戳
参考博客:
https://blog.csdn.net/qq_27886997/article/details/82982936
===启动报错===
Field processedDataDao in rexel.controller.RexelMiddlewareController required a bean of type 'rexel.dao.ProcessedDataDao' that could not be found. The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
问题原因:
包扫描路径不正确
@ComponentScan("rexel")
===启动报错===
Composite-id class must implement Serializable: rexel.entity.DViewVarNameDic
如果该实体类对应的表只有一个主键,即图中的id,把linkName上面的@Id注解删除即可,重新启动就不会报错了。
如果该实体类对应的表确实使用的两个字段(联合主键),则要求该实体类必须可序列化,该类要实现 Serializable 接口,并添加如下代码:
private static final long serialVersionUID = 1L;
public class DViewVarNameDic implements Serializable {
参考博客:
http://www.mamicode.com/info-detail-2681892.html
===启动报错===
Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: This class [class rexel.entity.DViewVarNameDicEntity] does not define an IdClass
解决办法:
在Entity类前面加上@IdClass()
===@Configuration和@Bean===
@Configuration底层是含有@Component ,所以@Configuration 具有和 @Component 的作用。
@Configuration可理解为用spring的时候xml里面的<beans>标签。
@Configuration注解可以达到在Spring中使用xml配置文件的作用。
@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的<beans>,作用为:配置spring容器(应用上下文)
参考博客:
https://blog.csdn.net/qq_36472252/article/details/86623630
===RestRemplate样例程序运行报错===
Caused by: org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class rexel.webservice.bean.ProcessedDataBean] and content type [text/html;charset=utf-8]
按照这个网址可以解决
https://www.jianshu.com/p/95bf08696cd7
然后再次运行,又会提示其他错误
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unrecognized token 'H24': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'H24': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
at [Source: (PushbackInputStream); line: 6, column: 20]
检查之后,发现是我在postman里定义的json格式不正确引起的。
Shit,多少有些2B了,暂时放过自己一次。
===增加了事务注解,但是无法回滚===
我这里发生的原因是用@Transactional(rollbackFor = Exception.class)标注的方法没有是public
参考博客:
https://blog.csdn.net/zdyueguanyun/article/details/80236401
===读取application.properties文件的几种方法===
第一种方式:使用@ConfigurationProperties(prefix = "com.zyd")注解在class头
第二种方式:使用@Value("${propertyName}")注解在变量上
第三种方式:使用Environment evn; env.getProperty("com.zyd.type2")
第四种方式:使用Properties properties = PropertiesLoaderUtils.loadAllProperties(propertyFileName);
参考博客:
https://www.cnblogs.com/FraserYu/p/11261916.html
===Http报头Accept与Content-Type的区别===
Http报头分为通用报头,请求报头,响应报头和实体报头。
1.Accept属于请求头, Content-Type属于实体头。
Http报头分为通用报头,请求报头,响应报头和实体报头。
请求方的http报头结构:通用报头|请求报头|实体报头
响应方的http报头结构:通用报头|响应报头|实体报头
2.Accept代表发送端(客户端)希望接受的数据类型。
比如:Accept:text/xml;
代表客户端希望接受的数据类型是xml类型
3.Content-Type代表发送端(客户端|服务器)发送的实体数据的数据类型。
比如:Content-Type:text/html;
代表发送端发送的数据格式是html。
二者合起来,
Accept:text/xml;
Content-Type:text/html
即代表希望接受的数据类型是xml格式,本次请求发送的数据的数据格式是html。
===运行报错===
Caused by: org.hibernate.AnnotationException: No identifier specified for entity: rexel.entity.AccessTokenEntity
at org.hibernate.cfg.InheritanceState.determineDefaultAccessType(InheritanceState.java:266) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.cfg.InheritanceState.getElementsToProcess(InheritanceState.java:211) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:781) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:254) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:230) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:273) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1214) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1245) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
问题原因:
当使用idclass时,实体中须有和idclass类中属性个数的主键,并且一致
参考博客:
https://blog.csdn.net/Mosqiote/article/details/89227931
===Springboot的entity,dao,controller,service层级理解===
1.Dao层:持久层,主要与数据库交互
DAO层首先会创建Dao接口,接着就可以在配置文件中定义该接口的实现类;
接着就可以在模块中调用Dao的接口进行数据业务的处理,而不用关注此接口的具体实现类是哪一个类,
Dao层的数据源和数据库连接的参数都是在配置文件中进行配置的。
2.Entity层:实体层,数据库在项目中的类
主要用于定义与数据库对象应的属性,提供get/set方法,tostring方法,有参无参构造函数。
3.Service层:业务层 控制业务
业务模块的逻辑应用设计,和DAO层一样都是先设计接口,再创建要实现的类,然后在配置文件中进行配置其实现的关联。
接下来就可以在service层调用接口进行业务逻辑应用的处理。
好处:封装Service层的业务逻辑有利于业务逻辑的独立性和重复利用性。
4.Controller层:控制层 控制业务逻辑
具体的业务模块流程的控制,controller层主要调用Service层里面的接口控制具体的业务流程,控制的配置也要在配置文件中进行。
Controller和Service的区别是:Controller负责具体的业务模块流程的控制;Service层负责业务模块的逻辑应用设计
5、View层
此层与控制层结合比较紧密,需要二者结合起来协同工发。View层主要负责前台jsp页面的表示
总结:
Controller层调用了Service层的方法,Service层调用Dao层的方法,其中调用的参数是使用Entity层进行传递的。
参考博客:
https://www.cnblogs.com/almm/p/10802419.html
===请求报错===
Invalid character found in method name. HTTP method names must be tokens
解决办法:
请求由https修改为http之后解决。
===后端如何将数据返回给前端?===
@RequestBody:
用于读取Http请求的body部分数据——就是我们的请求数据。比如json或者xml。然后把数据绑定到 controller中方法的参数上
@ReponseBody:
放在controller层的方法上,将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
使用时机: 当我们想让页面知道我们返回的数据不是按照html标签的页面来解析,而是其他某种格式的数据解析时(如json、xml等)使用。
===运行报错===
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:409) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1601) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
问题原因
在@Query注解中编写JPQL语句, 但必须使用@Modifying进行修饰。以通知SpringData,这是一个UPDATE或DELETE操作
其中,nativeQuery = true 就代表使用原始 sql
修改之后代码如下:
@Modifying
@Query(nativeQuery = true, value = "insert into COLLECT_SWITCH(collect) values (:#{#entity.collect})")
public void insert(@Param("entity") CollectSwitchEntity entity);
===运行错误===
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://3dd39ca6-40bd-41ae-a045-ff80d0e6aca8.mock.pstmn.io/openapi/ipm/wait/process/query": Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out
解决办法:
增加对RestRemplate连接时间的配置。
解决后代码
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory){
return new RestTemplate(factory);
} @Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(15000);
factory.setReadTimeout(15000);
return factory;
}
}
===mysql传入时间正确,但是插入到数据库时间错误,相差几个小时===
解决办法:
直接在数据库连接地址后面添加引号内的内容“&serverTimezone=GMT%2B8”
spring.datasource.url=jdbc:mysql://192.168.29.100:3306/rexel_hzzg?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
===saveAll为啥每次都要查询数据?===
原因请参考博客:
https://www.cnblogs.com/blog5277/p/10661096.html
解决办法:
自己写插入的语句,不适用JPA自带的saveAll方法。
====运行错误===
错误日志:
2019-11-22 16:20:13.862 ERROR 98860 --- [ scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task org.springframework.web.client.HttpClientErrorException$NotFound: 404 Not Found
at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:85) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:123) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:102) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
原因:
已经发布的系统,其中有一个quartz的定时器运行了一段时间后突然挂掉了。
并报错:Unexpected error occurred in scheduled task.
调查发现因为:定时器的动作是调用一个同步线程,而某一次该线程运行时间过长即锁未释放,而第二次定时器动作又并发执行了,所以就导致了冲突。
解决办法:
1、增加config配置
2、----------------------------不要使用https请求。。。。。。。。。。。。。
补充:
在博文最开始共享的代码中,我已经删除了ScheduleConfig的配置,代码中已经找不到这个配置了。
===mysql在台式机上安装报错(Windows10操作系统)===
mysql启动服务报错
Found option without preceding group in config file
问题原因:
mysql里面的配置文件my.ini文件格式是utf-8。
只要把my.ini文件格式改为ANSI就可以了。
===程序运行了一段时间之后,报错===
Hibernate: select collectswi0_.collect as collect1_1_ from COLLECT_SWITCH collectswi0_
Hibernate: select accesstoke0_.token as token1_0_, accesstoke0_.insertTime as insertTi2_0_ from ACCESS_TOKEN accesstoke0_ order by accesstoke0_.insertTime desc
2019-11-25 08:20:49.772 ERROR 15728 --- [pool-1-thread-2] o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task org.springframework.web.client.HttpClientErrorException$TooManyRequests: 429 Too Many Requests
at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:97) ~[spring-web-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:123) ~[spring-web-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:102) ~[spring-web-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63) ~[spring-web-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:785) ~[spring-web-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:743) ~[spring-web-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:717) ~[spring-web-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:605) ~[spring-web-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at rexel.schedule.MiddleWareSchedule.exchange(MiddleWareSchedule.java:318) ~[classes!/:0.0.1]
at rexel.schedule.MiddleWareSchedule.getProcessData(MiddleWareSchedule.java:218) ~[classes!/:0.0.1]
at rexel.schedule.MiddleWareSchedule.scheduleProcess(MiddleWareSchedule.java:111) ~[classes!/:0.0.1]
at rexel.schedule.MiddleWareSchedule$$FastClassBySpringCGLIB$$3847585e.invoke(<generated>) ~[classes!/:0.0.1]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:366) ~[spring-tx-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99) ~[spring-tx-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at rexel.schedule.MiddleWareSchedule$$EnhancerBySpringCGLIB$$3bdb64f9.scheduleProcess(<generated>) ~[classes!/:0.0.1]
at sun.reflect.GeneratedMethodAccessor96.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_77]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_77]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [na:1.8.0_77]
at java.util.concurrent.FutureTask.runAndReset(Unknown Source) [na:1.8.0_77]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source) [na:1.8.0_77]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) [na:1.8.0_77]
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_77]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_77]
at java.lang.Thread.run(Unknown Source) [na:1.8.0_77]
原因是potstman已经达到了模拟请求的极限,需要升级到专业版
You’ve reached your limit for mock requests. Upgrade to Pro for more.
===cron表达式===
cron一共有7位,但是最后一位是年,可以留空,所以我们一般可以只写6位:
第一位,表示秒,取值0-59
第二位,表示分,取值0-59
第三位,表示小时,取值0-23
第四位,日期天/日,取值1-31
第五位,日期月份,取值1-12
第六位,星期,取值1-7,星期一,星期二…注意:1表示星期天,2表示星期一。
第7为,年份,可以留空,取值1970-2099
样例:
每隔5秒执行一次:*/5 * * * * ?
每隔1分钟执行一次:0 */1 * * * ?
每天凌晨1点执行一次:0 0 1 * * ?
每天23点执行一次:0 0 23 * * ?
每月最后一天23点执行一次:0 0 23 L * ?
每月1号凌晨1点执行一次:0 0 1 1 * ?
每天3点5分执行:0 5 3 * * ?
每天3点5分执行,与上面作用相同:0 5 3 ? * *
每天3点的 5分,15分,25分,35分,45分,55分这几个时间点执行:0 5/10 3 * * ?
每周星期天,3点10分 执行,注:1表示星期天:0 10 3 ? * 1
每个月的第三个星期,星期天 执行,注:#号只能出现在星期的位置:0 10 3 ? * 1#3
在26分、29分、33分执行一次:0 26,29,33 * * * ?
每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?
===@Scope("prototype")===
spring中bean的scope属性,有如下5种类型:
1)singleton 表示在spring容器中的单例,通过spring容器获得该bean时总是返回唯一的实例
2)prototype表示每次获得bean都会生成一个新的对象
3)request表示在一次http请求内有效(只适用于web应用)
4)session表示在一个用户会话内有效(只适用于web应用)
5)globalSession表示在全局会话内有效(只适用于web应用)
在多数情况,我们只会使用singleton和prototype两种scope,如果在spring配置文件内未指定scope属性,默认为singleton。
===接口Service有多个实现类===
//接口.java
public interface DeService {
} //接口实现类1.java
@Service("ud")
public class DeServiceImplUD implements DeService{
} //接口实现类2.java
@Service("ug")
public class DeServiceImplUG implements DeService{
} //调用类.java
@Autowired
@Qualifier("ug")
private DeService ds;
===all elements are null===
使用spring jpa查询书库的时候,数据库中明明有数据,查询出来的结果却显示all elements are null。
可以看出,实际上List中有38条数据,只不过都没能正确转换为Entity。
后来调查原因是因为我用的PostgreSQL中数据有的字段为null,所以没能转换成功。