关于springboot:springbootmybatisplusdruid数据源SQLException问题

当我尝试应用数据源拜访mysql时,产生了这样的异样: java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:965) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3978) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3914) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:871) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.mysql.jdbc.MysqlIO.proceedHandshakeWithPluggableAuthentication(MysqlIO.java:1714) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1224) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2199) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2230) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2025) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:778) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47) ~[mysql-connector-java-5.1.47.jar:5.1.47] at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_181] at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_181] at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_181] at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_181] at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:386) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:330) ~[mysql-connector-java-5.1.47.jar:5.1.47] at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1596) ~[druid-1.1.16.jar:1.1.16] at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1662) ~[druid-1.1.16.jar:1.1.16] at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2601) ~[druid-1.1.16.jar:1.1.16]2022-05-27 17:45:02.559 ERROR 31428 --- [eate-1875532039] com.alibaba.druid.pool.DruidDataSource : create connection SQLException, url: jdbc:mysql://localhost:3306/db2022?useUnicode=true&characterEncoding=utf-8&useSSL=false, errorCode 1045, state 28000起因很低级:application.yml内容: ...

May 27, 2022 · 1 min · jiezi

关于springboot:记录后台遇到的两个小问题

specification查问不起作用写后盾的时候须要加一个specification查问,只返回属于该社区的数据。 于是我减少了如图红框中的查问,调用了and函数。 specification.and(VehicleSpecs.belongToCommunity(district.getId()));然而执行后发现,这条查问没有依照想法获取到查问到数据,相当于这条查问并没有作用。 在打断点之后,发现的确进入了查问函数里。 测试了很多遍还是如此,这条查问语句并没有起作用。 起初查谷歌之后发现有人和我遇到同样的问题。解决办法很简略:让specification等于and函数返回值 也就是这样: specification = specification.and(VehicleSpecs.belongToCommunity(district.getId()));而后回过头看and函数的申明才发现:返回的是一个Specification类型的数据。也就是说,我并没有保留这个数据,所以查问生效了。应该从新给本地变量赋值。这样能力使查问真正增加下来。 之后回过头来想想,我没有想到从新赋值的起因,可能是习惯了下图中的形式,即调用了函数,就真正地把数据增加了进去,不必再去从新赋值。 总结总结来说还是须要真正看函数的申明,查看它的返回值,以确定是否须要执行相干的操作。因为这个函数的用法和返回值都写在了申明中。 单元测试数据不统一在单元测试中,第187行产生的谬误。 MockMvc返回的值与冀望的值不统一 然而去控制台一看:值是雷同的。期望值是0,理论值也是0。这就很奇怪了,期望值和理论值雷同,为什么两者没有通过判断呢。 很容易分割到是类型出了问题。 测试发现,Long,Integer, String, 都通过了。 没通过的是Short类型的数据,即红框中的数据。 起初在前面加上 .toString()能失常通过。 这里mvc的json类型的数据是string类型, 与short类型数据判断的时候失败了,可能是两者不能失常辨认。

May 23, 2022 · 1 min · jiezi

关于springboot:SpringBoot-项目-全局拦截异常不生效

问题形容1、我的项目为微服务项目,新增加的模块中,在业务代码中,有抛出异样代码,代码示例为 throw new BusinessException("此处抛出了一个异样!");2、该我的项目,有一个公共模块(common),改模块中申明了吹全局异样的代码,代码示例如下: @ControllerAdvicepublic class BusinessExceptionHandler { /** * 解决自定义的业务异样 * * @param e 异样 * @return */ @ResponseBody @ExceptionHandler(value = BusinessException.class) public R TestExceptionHandler(BusinessException e) { R r = new R(); if (e.getCode() == 0) { r.put("code", R.CODE_500); } else { r.put("code", e.getCode()); } r.put("msg", e.getMessage()); return r; }}3、在测试的过程中,运行了,抛出异样的代码,然而,公共类中解决全局异样的类并没有失效。 问题剖析1、呈现以上问题,很显著的一个中央是,上述,公共类中的全局异样解决没有失效。2、从原理上登程,来剖析问题,咱们都晓得的是,对于SpringBoot我的项目,启动时默认,会扫描的到的类为该启动类所在的文件夹及其文件夹的子目录;当然,咱们也能够设置 @SpringBootApplication(scanBasePackages = {“cn.com.test”})来设置扫描范畴。3、自己我的项目中遇到的问题点是,我的项目示例如下:新增加的模块,启动类RestApplication所在的包为"com.hs.tutu.test",公共类,所在的包为"com.hs.tutu.common",所以,启动类代码如下设置 @SpringBootApplicationpublic class RestApplication { public static void main(String[] args) { SpringApplication.run(RestApplication.class,args); }}公共类中的全局异样是不失效的,启动时,没有扫描到解决全局异样的类。 解决方案1、能够将我的项目启动类,往上提一层,放到"com.hs.tutu"包中,成果如下:2、能够通过设置,启动类包扫描门路,代码示例如下: @SpringBootApplication(scanBasePackages = "com.hs.tutu")public class RestApplication { public static void main(String[] args) { SpringApplication.run(RestApplication.class,args); }}

May 17, 2022 · 1 min · jiezi

关于springboot:win-server-部署前后端分离项目springboot-vue-android

win server 部署前后端拆散我的项目(springboot + vue + android)记录一下,也给小白一些参考首先得会开发 springboot、vue、android 我的项目才须要看本文 一、后期筹备1.轻量级应用服务器2.域名3.备案二、服务器部署 springboot 我的项目0.开发小记录0.1 Maven 应用maven 下载cmd里敲 mvn -version 验证是否胜利在该目录下新建一个文件夹 maven_repository D:\software\work\apache-maven-3.8.5关上该文件,增加本地仓库 D:\software\work\apache-maven-3.8.5\conf\settings.xml <localRepository>D:\software\work\apache-maven-3.8.5\maven_repository</localRepository>批改为阿里云私服 <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror>IDEA配置 settings 里搜寻 maven 0.2 mysql 学习阶段应用简洁版即可mysql 1.服务器装置 navicat2.在本人电脑上连贯服务器的 mysql批改服务器 mysql 中的 user 表(不然的话会报错 1130 - Host XXX is not allowed to connect to this MySQL server)将 User 为 root 一行的 Host 批改为 % 而后新建查问执行以下命令 flush privileges;3.导入本人的 sql 文件4.将 springboot 我的项目打包 jar 并在服务器上运行应用idea,顺次双击 clean complie package将打包好的 jar 复制粘贴进服务器中进入jar目录,cmd,运行,或将其改为 .bat,之后双击运行即可 ...

May 15, 2022 · 2 min · jiezi

关于springboot:SpringbootMybatis总结

待补充这里 user 表齐全能够不写反引号,写反引号次要是为了不便咱们辨别,这是数据库的一个表。 编写 Mapper.xml 文件次要留神三点: namespace绝对应id绝对应resultType绝对应目前咱们所讲的 resultType 返回繁多类型的值,包含根底类型 String、Integer、Long,还有定义好的 Class 对象。 resultMap 则能够返回多个类型的值,适宜多表连贯查问。resultMap 的具体用法能够去官网文档中学习,这里咱们不做过多的理解。 8.编写Service咱们须要在实现类中应用 @Service 注解,能力被 SpringBoot 扫描,在 Controller 中应用 @Autowired 注入 在 service 目录中新建 UserService 类

May 12, 2022 · 1 min · jiezi

关于springboot:netsfjsqlparserparserParseException-Encountered-unexpected

原文地址 写在后面最近开发过程中,在where条件中应用IF函数,在MySQL数据库中,应用Navicat运行没有问题,然而运行我的项目的时候,死活过不去,始终报错,起初一番折腾找到了解决方案,所以,以防后续再呈现相似问题,仅做记录! 阐明:我的项目为SpringBoot我的项目,长久化层框架应用的是Mybatis-plus(版本为3.0.7)1.问题复现1.1 SQL语句执行后果 1.2 Mapper层对应接口 1.3 Mabyties对应xml 1.4 报错信息 2. 问题起因 针对这个问题,在网上查了相干文档,Mybatis-plus官网说是框架中应用到了多租户性能,Mybatis-plus 会 进行数据权限的过滤,然而有些接口,其实并不想被多租户过滤,所以要对该条sql,进行租户放行。对于这块Mybatis-plus官网阐明了 SqlParserFilter sql 解析过滤器,当然对这部分感兴趣的小伙伴们,能够去Mybatis-plus官网查看相干源码,我这里就不在具体阐明了。 阐明:多租户:多个用户间应用同一套程序,但每个用户之间实现数据隔离3.问题解决参考Mybatis-plus官网,在Mapper层接口办法上 退出注解 @SqlParser(filter=true)官网截图如下 加完注解之后的Mapper层接口办法如下: @SqlParser(filter = true)List<EmpWhiteList> getAdminList(@Param("empId") String empId, @Param("timeDate") String timeDate);加完此注解之后,因为我的项目的Mybatis-plus版本为3.0.7,所以这里还要再在application.yml文件中增加下列配置能力失效 阐明:如果Mybatis-plus版本是3.1.1至3.4.0以下版本能够间接 增加此注解 即可,3.1.1以下版本须要增加如下配置:# 开启 SQL 解析缓存注解失效mybatis-plus: global-config: sql-parser-cache: truemybatis-plus3.4.0及以上版本留神: @SqlParser(filter = true) 在mybatis-plus最新版本3.4.0及以上版本中被标记为已过期,具体代替计划,官网已给出 @Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE, ElementType.METHOD})public @interface InterceptorIgnore { ...}对于此注解官网给出如下应用办法: 鉴于此,如果我的项目引入的MybatisPlus版本为3.4.0及以上,则多租户屏蔽某个特定mapper接口的办法,则应用如下解决方案: @InterceptorIgnore(tenantLine = "true")List<EmpWhiteList> getAdminList(@Param("empId") String empId, @Param("timeDate") String timeDate);

May 10, 2022 · 1 min · jiezi

关于springboot:SpringBoot基础

SpringBoot根底从Spring到SpringBootSpring通过IOC与AOP实现了企业级的开发框架,尽管组件代码是轻量级的,然而配置文件却是重量级的,Spring Boot则简化Spring利用开发,基于约定大于配置(为大部分配置组件提供了默认配置)的思维,just run 就能创立一个独立的,产品级别的利用 SpringBoot框架并不是微服务框架,只是为微服务框架的组件构建提供了一个很好的脚手架SpringBoot提供了J2EE一站式解决方案;Spring Cloud提供了分布式整体解决方案Spring生态Spring严格来说是一个生态,而非仅仅几个常见的框架,基本上笼罩了以下几个次要场景的开发 web开发 Spring Framework数据拜访 Spring Data安全控制 Spring Security分布式 Spring CloudSpring Session..音讯服务 Spring AMQP批处理 Spring Batch在大型企业中,因为业务简单、数据量大、数据格式不同、数据交互格局繁冗,并非所有的操作都能通过交互界面进行解决。而有一些操作须要定期读取大批量的数据,而后进行一系列的后续解决。这样的过程就是批处理...能够说Spring以一己之力晋升了整个Java的开发生态,使得Java语言在支流开发场景中都能大显神通,正如Spring官网的首页图展现的那样 <img src="https://images.demoli.xyz/image-20210924220823740.png" alt="image-20210924220823740" style="zoom:67%;" /> SpringBoot存在的意义一般来说,Spring生态的学习路线都是从SSM(Spring、Spring MVC、MyBatis)到SpringBoot,SSM中的配置天堂是升高开发效率的微小阻碍;除此之外,上述说的Spring生态的泛滥性能的搭建与配合应用同样意味着大量的配置,是否简化配置,甚至做到主动配置(约定大于配置的思维),以晋升业务开发效率?SpringBoot应运而生。具体的劣势在以下几个方面: 能够创立独立的Spring利用内嵌Web服务器基于starter的场景主动配置主动配置Spring与第三方性能提供生产级别的监控、健康检查,内部化配置无代码生成,无需编写XMLSpringBoot的毛病 版本迭代快封装比拟深,查看源码难度比拟高SpringBoot2.0作为SpringBoot的新一代版本,SpringBoot2.0在整个框架结构设计上都有重大降级,次要包含以下两局部:响应式编程<img src="https://images.demoli.xyz/image-20210924223917397.png" alt="image-20210924223917397" /> 提出了响应式技术栈,即以异步非阻塞的形式使得整个框架可能以更少的系统资源解决更多的并发申请,对应的底层Web开发框架是Spring WebFlux,而不是传统的同步阻塞式的SpringMVC,这一部分可参考后续对于[Spring WebFlux的学习介绍]()源码设计调整齐全基于JDK8构建,同时兼容JDK11甚至Java17,基于一些新的Java个性对外部源码进行了从新设计,比方JDK8之前,接口没有默认办法实现的特色,导致接口的实现类不得不实现全副的接口办法,即使只应用其中几个办法,为了解决此问题,Spring中大量应用的适配器模式,应用适配器实现接口办法为空办法,再让子类去重写办法,而在JDK8后,一个default关键字就解决了,实现类无必要实现全副办法,因而大量的adapter就隐没了HelloWorld我的项目环境配置首先依照SpringBoot文档要求保障JDK版本为8或以上版本,Spring Framework版本、maven以及gradle版本参考要求即可 可参考具体版本的SpringBoot文档的Getting Started页面,比方2.6.5版本我的项目实现IDEA创立maven我的项目引入starters <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.5</version></parent><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency></dependencies>父工程对立治理可能应用到的各个组件的版本导入Web场景启动器以实现Web利用开发创立入口类与Controller @SpringBootApplicationpublic class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); }}@RestControllerpublic class HelloController { @RequestMapping("/hello") public String handleHello() { return "Hello SpringBoor 2"; }}与Spring MVC开发的代码编写统一,最大的不同在于无需增加大量的配置留神业务代码的包应和入口类在同一个包下,否则无奈解析业务代码中的的注解配置启动运行 间接启动入口程序即可开启内置的服务器提供Web服务,实现本地测试自定义配置 ...

May 9, 2022 · 7 min · jiezi

关于springboot:盘古开发框架集成-ShenYu-网关实现-Dubbo-泛化调用

盘古开发框架下实现微服务网关的缺省姿态为基于 pangu-web 模块的传统接口调用模式,具体请参考文档:如何公布微服务 (API 网关)。本文提供另外一种通过集成Apache ShenYu 实现网关泛化调用 Dubbo 服务将其公布为 HTTP 接口的可选办法。 ShenYu 网关介绍ShenYu 网关基于 Webflex 非阻塞模型通过泛化调用后端 Dubbo 服务。依赖 Netty 不须要 Servlet 容器,不须要引入服务接口包即可通过 Dubbo 泛化调用服务接口的形式就能够将后端 Dubbo 服务转换为 HTTP API。同时网关反对鉴权、动静限流、熔断、防火墙、灰度公布等。 相干名词解释shenyu-admin 网关插件和元数据信息配置管理后盾。独立 JAR,须要独自部署。shenyu-gateway 网关模块,代理 Http 申请,泛化调用后端 Dubbo 服务。此模块负责接管 Http 申请。数据同步 数据同步是指在 ShenYu-Admin 后盾操作数据当前,应用何种策略将数据同步到 ShenYu Gateway 网关模块。ShenYu 以后反对 ZooKeeper、WebSocket、Http 长轮询、Nacos 、Etcd 和 Consul 进行数据同步。盘古开发应用的是 WebSocket 形式进行数据同步。插件 ShenYu 应用插件化设计思维,实现插件的热插拔。内置丰盛的插件,包含 RPC 代理、熔断和限流、权限认证、监控等等。选择器 每个插件可设置多个选择器,对流量进行初步筛选。规定 每个选择器可设置多个规定,对流量进行更细粒度的管制。网关调用结构图 ShenYu 网关实战ShenYu 网关提供的性能十分多,这里咱们只关注 HTTP 申请代理性能。即代理前端 HTTP 申请,通过 Dubbo 泛化调用后端 Dubbo 服务。 ...

May 8, 2022 · 2 min · jiezi

关于springboot:SpringBoot的浅浅配置和小整合

SpringBoot的浅浅配置和小整合本文如题,就是浅浅记录一下学习的过程中一些过程,比较简单,并没有多少深度。谢谢!SpringBoot创立从IDEA中新建我的项目或者模块。留神jdk版本,个别不超过你的环境jdk。 抉择要加载的依赖项。 SpringBoot的配置文件SpringBoot的配置文件能够用 application.propertiesapplication.ymlapplication.yaml具体配置属性能够到https://docs.spring.io/spring...查看。 三种配置有优先关系,从.properties, .yml, .yaml优先关系递加。然而又是相互层叠的。能够略微举个例子。比方:三个文件都配置了端口号,那失效的就是依照优先级来的。然而三个文件都配置了独有的配置,那这三个配置都会失效。咱们个别应用的是.yml,比拟不便简略。能够看看具体的配置例子。 spring: datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=GMT%2B8&useSSL=false username: root password: root在配置文件中也能够应用属性名援用形式援用属性 baseDir: /usr/local/firecenter:dataDir: ${baseDir}/datatmpDir: ${baseDir}/tmplogDir: ${baseDir}/logmsgDir: ${baseDir}/msgDir咱们能够应用@Value注解配合SpEL读取单个数据,如果数据存在多层级,顺次书写层级名称即可。 然而须要整体读取下面的enterprise,就能够用@ConfigurationProperties这个注解 新建一个类来封装数据。@ConfigurationProperties(prefix = "enterprise")public class Enterprise {private String name;private Integer age;private String[] subject; }再通过主动拆卸,这样就好了。 @Autowiredprivate Enterprise enterprise;SpringBoot的一些小型整合整合Junit 默认IDEA的test下就有,察看代码能够看到@SpringBootTest这个注解须要留神的是测试类如果存在于疏导类所在包或子包中无需指定疏导类测试类如果不存在于疏导类所在的包或子包中须要通过classes属性指定疏导类。 @SpringBootTest(classes = Springboot03JunitApplication.class)整合Mybatis以及Druid 首先须要导入驱动和框架-而后配置属性,这里须要留神的是,因为导入的驱动是8.x高版本,之前我用的5.x都是不须要配置时区的,但这里须要配置时区。并且驱动也最好换成com.mysql.cj.jdbc.Driver,要不然会有一些小正告。 spring: datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=GMT%2B8&useSSL=false username: root password: root后言差不多水完了吧,后续可能要一段时间能力持续学习相干常识了。大略到寒假能力持续学习。 相干代码CODE

May 6, 2022 · 1 min · jiezi

关于springboot:如何基于盘古框架开发Dubbo微服务应用

本文介绍如何基于盘古开发框架开发一个微服务利用。文中所述仅为搭建一个微服务利用的根本框架(服务注册&服务发现),如要减少配置核心、网关代理、数据长久化、缓存等能力请参考使用指南的相干章节。 服务提供者装置相干盘古模块<!-- 盘古 Parent --><parent> <groupId>com.gitee.pulanos.pangu</groupId> <artifactId>pangu-parent</artifactId> <version>latest.version.xxx</version> <relativePath/></parent><!-- 根底模块 --><dependency> <groupId>com.gitee.pulanos.pangu</groupId> <artifactId>pangu-spring-boot-starter</artifactId></dependency><!-- Dubbo模块 --><dependency> <groupId>com.gitee.pulanos.pangu</groupId> <artifactId>pangu-dubbo-spring-boot-starter</artifactId></dependency><!-- 服务接口包 --><dependency> <groupId>com.gitee.pulanos.pangu</groupId> <artifactId>pangu-examples-dubbo-api</artifactId> <version>1.0.0</version></dependency>盘古框架微服务交互基于 Dubbo 提供的面向接口代理的高性能 RPC 调用能力。因而,对于外部服务模块之间的交互调用,不论是服务的提供者还是服务消费者,都须要依赖 API 服务接口包。当然,对于网关而言,应用的是泛化调用,也就是说当网关模块作为微服务消费者的时候是不须要依赖服务提供者的接口包的。本地配置为便于了解,本文基于本地配置的形式编写。若改为规范的 Nacos 配置核心模式,请参阅:配置核心 章节。spring.application.name=pangu-examples-dubbo-servicedubbo.protocol.name=dubbodubbo.protocol.port=20880dubbo.consumer.timeout=5000#服务注册核心地址dubbo.registry.address=nacos://${nacos.server-addr}?namespace=${nacos.namespace}dubbo.consumer.check=false实现服务接口UserEntity findUserEntity(Long id);@Service(version = "1.0.0", group = "pangu-showcases-dubbo-service")public class UserServiceImpl implements UserService { @Override public UserEntity findUserEntity(Long id) { log.info("参数ID:{}", id); UserEntity userEntity = new UserEntity(); userEntity.setId(id); userEntity.setName("云南码农大熊"); return userEntity; }}启动入口@EnableDubbo@SpringBootApplicationpublic class DubboProviderApplication { public static void main(String[] args) { PanGuApplicationBuilder.init(DubboProviderApplication.class).run(args); }}通过 @EnableDubbo 注解开启 Dubbo 反对。因为 Dubbo 的应用 netty 作为底层网络通信,决定了盘古微服务利用启动和提供服务并不需要依赖 Servlet 容器。 ...

May 5, 2022 · 1 min · jiezi

关于springboot:SpringBoot多数据源事务解决方案

背景之前有文章提供了springboot多数据源动静注册切换的整合计划,在后续应用过程中,发现在事务管制中有多种bug产生,决定对此问题进行剖析与解决 前情提要多数据源切换流程结构图如下所示,蕴含几个组成元素 自定义的数据源配置解决,通过DruidDataSource对象动静注册到零碎中自定义数据源标识注解与切面数据源切换时的上下文线程变量持有者自定义AbstractRoutingDataSource,实现数据源路由切换 问题剖析在Controller退出@Transitional注解后,数据源切换会生效,只会操作主库,查问材料后解决方案是将切面的Order设置为-1使之执行程序在事务管制拦挡之前,批改后证实无效,然而后续再次切换别的库或者进行主库操作有效,拿到的connection始终是第一次切换后的库对应的连贯 剖析代码后发现AbstractRoutingDataSource只负责提供getConnection这一层级,然而后续对connection的操作无奈跟踪,我的项目框架mybatis和jdbcTemplate混合应用,后续操作在spring层面对于事务/数据源/连贯这三者的逻辑层面操作是雷同的,jdbcTemplate代码较为简单,所以以此为切入点进一步剖析 通过断点调试会发现sql语句的执行最终会落到execute办法,办法中开始就是通过DataSourceUtils.getConnection获取连贯,这里就是咱们须要追踪的中央,点进去发现跳转到doGetConnection办法,这外面就是咱们须要剖析的具体逻辑 第一行获取的ConnectionHolder就是以后事务对应的线程持有对象,因为咱们晓得,事务的实质就是办法外部的sql执行时对应的是同一个数据库connection,对于不同的嵌套业务办法,惟一雷同的是以后线程ID统一,所以咱们将connection与线程绑定就能够实现事务管制 点进getResource办法,发现dataSource是作为一个key去一个Map汇合里取出对应的contextHolder 到这里咱们如同发现点什么,之前对jdbcTemplatechu实例化设定数据源间接赋值自定义的DynamicDataSource,所以在事物中每次咱们获取connection根据就是DynamicDataSource这个对象作为key,所以每次都会一样了!! @Bean public JdbcTemplate jdbcTemplate(){ JdbcTemplate jdbcTemplate = null; try{ jdbcTemplate = new JdbcTemplate(dynamicDataSource()); }catch (Exception e){ e.printStackTrace(); } return jdbcTemplate; }后续针对mybatis查找了相干材料,事务管制默认实现是SpringManagedTransaction,源码查看后发现了相熟的DataSourceUtils.getConnection,证实咱们的剖析方向是正确的 解决方案jdbcTemplate自定义操作类继承jdbcTemplate重写getDataSource,将咱们获取的DataSource这个对应的key指定到理论切换库的数据源对象上即可 public class DynamicJdbcTemplate extends JdbcTemplate { @Override public DataSource getDataSource() { DynamicDataSource router = (DynamicDataSource) super.getDataSource(); DataSource acuallyDataSource = router.getAcuallyDataSource(); return acuallyDataSource; } public DynamicJdbcTemplate(DataSource dataSource) { super(dataSource); }} public DataSource getAcuallyDataSource() { Object lookupKey = determineCurrentLookupKey(); if (null == lookupKey) { return this; } DataSource determineTargetDataSource = this.determineTargetDataSource(); return determineTargetDataSource == null ? this : determineTargetDataSource; }mybatis自定义事务操作类,实现Transaction接口,替换TransitionFactory,这里的实现与网上的解决方案略有不同,网上是定义三个变量,datasource(动静数据源对象)/connection(主连贯)/connections(从库连贯),然而框架须要mybatis和jdbctemplate进行对立,mybatis是从connection层面管制,jdbctemplate是从datasource层面管制,所以全副应用键值对存储 ...

May 1, 2022 · 2 min · jiezi

关于springboot:SpringBoot集成mybatis拦截器修改表名

背景公司的框架是基于mysql5.7开发的,最近有一个利用我的项目部署在linux零碎上,应用的是mysql8.0,装置时未开启大小写敏感疏忽,客户又不容许重装mysql环境,导致一些框架代码和业务代码中表名应用大写的中央会呈现表名找不不到的状况,所以须要进行对立解决 自定义SQLAST适配器自定义ASTVisitorAdapter对表名进行批改 public class MySqlExportTableAliasVisitor extends MySqlASTVisitorAdapter { @Override public boolean visit(SQLExprTableSource x) { SystemConfig systemConfig = SpringBootBeanUtil.getBean(SystemConfig.class); if(systemConfig.getDbTableNameProxy().equals("lowcase")){ x.setExpr(x.getTableName().toLowerCase()); }else if(systemConfig.getDbTableNameProxy().equals("upcase")){ x.setExpr(x.getTableName().toUpperCase()); } return true; }}自定义Mybatis拦截器通过BoundSql获取sql语句,应用Druid的SQLUtils对sql语句进行结构化分析,表名批改实现后再从新复制sql语句 @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})public class SQLTableNameHandleInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { DataBaseInfoUtil dataBaseInfoUtil = SpringBootBeanUtil.getBean(DataBaseInfoUtil.class); if(dataBaseInfoUtil.checkOpenTableNameHandle()){ StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory()); BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql"); String sql = boundSql.getSql(); List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL); MySqlExportTableAliasVisitor visitor = new MySqlExportTableAliasVisitor(); for (SQLStatement stmt : stmtList) { stmt.accept(visitor); } String handleSQL = SQLUtils.toSQLString(stmtList, JdbcConstants.MYSQL); metaStatementHandler.setValue("delegate.boundSql.sql", handleSQL); } return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { }}注册自定义Myabits拦截器@Configurationpublic class FrameMyBatisPluginConfig { @Bean @Conditional({SQLTableNameHandleInterceptorCondition.class}) public String SQLTableNameHandleInterceptor(SqlSessionFactory sqlSessionFactory) { //实例化插件 SQLTableNameHandleInterceptor sqlTableNameHandleInterceptor = new SQLTableNameHandleInterceptor(); //创立属性值 Properties properties = new Properties(); properties.setProperty("prop1","value1"); //将属性值设置到插件中 sqlTableNameHandleInterceptor.setProperties(properties); //将插件增加到SqlSessionFactory工厂 sqlSessionFactory.getConfiguration().addInterceptor(sqlTableNameHandleInterceptor); return "interceptor"; }}

May 1, 2022 · 1 min · jiezi

关于springboot:两种方式实现-SpringBoot-中数据库密码加密

第一种Jasypt加密maven依赖不同的spring boot版本引入的jasypt版本不同 <!-- Jasypt加密 -->spring boot 版本号1依赖<dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot-starter</artifactId> <version>2.0.0</version></dependency>spring boot 版本号2依赖<dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot-starter</artifactId> <version>3.0.3</version></dependency>在配置核心减少相干配置jasypt.encryptor.password=henghe #加密密钥 或者 为了避免salt(盐)泄露,反解出明码.能够在我的项目部署的时候应用命令传入salt(盐)值: java -jar xxx.jar -Djasypt.encryptor.password=henghe如果您正在学习Spring Boot,那么举荐一个连载多年还在持续更新的收费教程:http://blog.didispace.com/spr...将application.yml或配置核心中重要的配置改为加密格局 password: ENC(tnJpIM6iACWO/wRI//7XsbBqy/Mpx6MG1hXe4S7U4cNWmGhajnUSeXmBmQiniKEU)springboot程序在启动会自动检测appliction.yml或者配置核心中有ENC(xx)的配置并做解密加解密的测试类import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;import org.jasypt.encryption.pbe.StandardPBEByteEncryptor;import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;/** * @Created with Intellij IDEA * @Author : * @Date : 2018/5/18 - 10:37 * @Copyright (C), 2018-2018 * @Descripition : Jasypt平安框架加密类工具包 */public class JasyptUtils { /** * Jasypt生成加密后果 * * @param password 配置文件中设定的加密明码 jasypt.encryptor.password * @param value 待加密值 * @return */ public static String encryptPwd(String password, String value) { PooledPBEStringEncryptor encryptOr = new PooledPBEStringEncryptor(); encryptOr.setConfig(cryptOr(password)); String result = encryptOr.encrypt(value); return result; } /** * 解密 * * @param password 配置文件中设定的加密明码 jasypt.encryptor.password * @param value 待解密密文 * @return */ public static String decyptPwd(String password, String value) { PooledPBEStringEncryptor encryptOr = new PooledPBEStringEncryptor(); encryptOr.setConfig(cryptOr(password)); String result = encryptOr.decrypt(value); return result; } /** * @param password salt * @return */ public static SimpleStringPBEConfig cryptOr(String password) { SimpleStringPBEConfig config = new SimpleStringPBEConfig(); config.setPassword(password); config.setAlgorithm(StandardPBEByteEncryptor.DEFAULT_ALGORITHM); config.setKeyObtentionIterations("1000"); config.setPoolSize("1"); config.setProviderName(null); config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator"); config.setStringOutputType("base64"); return config; } public static void main(String[] args) { // 加密 System.out.println(encryptPwd("EbfYkitulv73I2p0mXI50JMXoaxZTKJ7", "root@1234")); // 解密// mysql@1234// System.out.println(decyptPwd("EbfYkitulv73I2p0mXI50JMXoaxZTKJ7", "bgWQ4OfVCUJ1ExsqNhGV+KKBgpx8alv+"));// root@1234// System.out.println(decyptPwd("EbfYkitulv73I2p0mXI50JMXoaxZTKJ7", "tdHzge8YvviOJaiV/+P6uQ9wgB44D1aH")); }}另外,想进外企的小伙伴留神啦,我为大家精心筹备了一份外企面经材料,包含eBay,Shopee等(之前分享的大厂面经不蕴含这部分内容),关注公众号后端面试那些事,回复:外企2022,即可支付! ...

April 28, 2022 · 3 min · jiezi

关于springboot:SpringBoot-内置工具类

断言 断言是一个逻辑判断,用于查看不应该产生的状况 Assert 关键字在 JDK1.4 中引入,可通过 JVM 参数-enableassertions开启 SpringBoot 中提供了 Assert 断言工具类,通常用于数据合法性检查// 要求参数 object 必须为非空(Not Null),否则抛出异样,不予放行// 参数 message 参数用于定制异样信息。void notNull(Object object, String message)// 要求参数必须空(Null),否则抛出异样,不予『放行』。// 和 notNull() 办法断言规定相同void isNull(Object object, String message)// 要求参数必须为真(True),否则抛出异样,不予『放行』。void isTrue(boolean expression, String message)// 要求参数(List/Set)必须非空(Not Empty),否则抛出异样,不予放行void notEmpty(Collection collection, String message)// 要求参数(String)必须有长度(即,Not Empty),否则抛出异样,不予放行void hasLength(String text, String message)// 要求参数(String)必须有内容(即,Not Blank),否则抛出异样,不予放行void hasText(String text, String message)// 要求参数是指定类型的实例,否则抛出异样,不予放行void isInstanceOf(Class type, Object obj, String message)// 要求参数 subType 必须是参数 superType 的子类或实现类,否则抛出异样,不予放行void isAssignable(Class superType, Class subType, String message)对象、数组、汇合ObjectUtils ...

April 28, 2022 · 4 min · jiezi

关于springboot:WGCLOUD如何配置某些磁盘不用发送告警通知

有一个简略的自定义办法,新建一个json文件,名称为hostWarnDiy.json,这个名称不能批改的,不然改了零碎辨认不了,内容格局如下如下,记得把IP和磁盘改为本人的理论值,多余的主机能够删除的: [ { "hostname":"192.168.1.2", "diskBlock":"'F:'" }, { "hostname":"192.168.1.3", "diskBlock":"'E:','F:'" }, { "hostname":"192.168.1.9", "diskBlock":"/snap/**" }]如上编辑实现后,将其保留到server/config/下,而后重启server就能够了 好了,如上就是自定义每个主机的不须要告警的盘符,咱们试试吧 还有一种是针对所有主机设置的办法,在server/config/application.yml中如下配置,批改后须要重启server失效 #不须要告警磁盘在此屏蔽,多个盘符用,隔开,如/boot,/dev。反对Ant门路匹配规定,如/dev/**。特殊符号用单引号,如'C:' diskBlock: /dev,/snap/**,'F:'或者不须要磁盘告警,也能够把告警开关关掉,在server/config/application.yml中如下配置,批改后须要重启server失效 #磁盘使用率告警开关,yes开启,no敞开 diskWarnMail: no

April 28, 2022 · 1 min · jiezi

关于springboot:Spring-Boot-实现各种参数校验非常实用

本文会具体介绍Spring Validation各种场景下的最佳实际及其实现原理,死磕到底! 简略应用Java API标准 (JSR303) 定义了Bean校验的规范validation-api,但没有提供实现。hibernate validation是对这个标准的实现,并减少了校验注解如@Email、@Length等。Spring Validation是对hibernate validation的二次封装,用于反对spring mvc参数主动校验。接下来,咱们以spring-boot我的项目为例,介绍Spring Validation的应用。 引入依赖如果spring-boot版本小于2.3.x,spring-boot-starter-web会主动传入hibernate-validator依赖。如果spring-boot版本大于2.3.x,则须要手动引入依赖: <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.1.Final</version> </dependency> 对于web服务来说,为避免非法参数对业务造成影响,在Controller层肯定要做参数校验的!大部分状况下,申请参数分为如下两种模式: POST、PUT申请,应用requestBody传递参数;GET申请,应用requestParam/PathVariable传递参数。上面咱们简略介绍下requestBody和requestParam/PathVariable的参数校验实战! requestBody参数校验POST、PUT申请个别会应用requestBody传递参数,这种状况下,后端应用 DTO 对象进行接管。只有给 DTO 对象加上@Validated注解就能实现主动参数校验。比方,有一个保留User的接口,要求userName长度是2-10,account和password字段长度是6-20。如果校验失败,会抛出MethodArgumentNotValidException异样,Spring默认会将其转为400(Bad Request)申请。 DTO 示意数据传输对象(Data Transfer Object),用于服务器和客户端之间交互传输应用的。在 spring-web 我的项目中能够示意用于接管申请参数的Bean对象。 如果您正在学习Spring Boot,那么举荐一个连载多年还在持续更新的收费教程:http://blog.didispace.com/spr...在DTO字段上申明束缚注解@Data public class UserDTO { private Long userId; @NotNull @Length(min = 2, max = 10) private String userName; @NotNull @Length(min = 6, max = 20) private String account; @NotNull @Length(min = 6, max = 20) private String password; } 在办法参数上申明校验注解@PostMapping("/save") public Result saveUser(@RequestBody @Validated UserDTO userDTO) { return Result.ok(); } 这种状况下,应用@Valid和@Validated都能够。 ...

April 27, 2022 · 5 min · jiezi

关于springboot:Spring-Boot-Feign调用原理探究

单元测试类如下: @SpringBootTest(classes = Application.class)@RunWith(SpringRunner.class)public class Test{ @Resource private AdSupportAccount adSupportAccount; @Test publict void test(){ adSupportAccount.list(accountInfoQuery); }}Feign申明如下: @FeignClient(value = "account-provider", url = "${account}")public interface AdSupportAccount { /** * 分页查问account 列表 * * @param accountInfoQuery * @return */ @PostMapping("accountInfo/list") KkbResponse<Map<String, Object>> list(@RequestBody AccountInfoQuery accountInfoQuery);}debug能够看到AdSupportAccount实例其实被代理类FeignINvocationHandler持有 registerBeanDefinition:929, DefaultListableBeanFactory (org.springframework.beans.factory.support)registerBeanDefinition:164, BeanDefinitionReaderUtils (org.springframework.beans.factory.support)registerFeignClient:258, FeignClientsRegistrar (org.springframework.cloud.openfeign)registerFeignClients:219, FeignClientsRegistrar (org.springframework.cloud.openfeign)registerBeanDefinitions:144, FeignClientsRegistrar (org.springframework.cloud.openfeign)registerBeanDefinitions:86, ImportBeanDefinitionRegistrar (org.springframework.context.annotation)lambda$loadBeanDefinitionsFromRegistrars$1:384, ConfigurationClassBeanDefinitionReader (org.springframework.context.annotation)accept:-1, 1868288866 (org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$$Lambda$276)forEach:684, LinkedHashMap (java.util)loadBeanDefinitionsFromRegistrars:383, ConfigurationClassBeanDefinitionReader (org.springframework.context.annotation)loadBeanDefinitionsForConfigurationClass:148, ConfigurationClassBeanDefinitionReader (org.springframework.context.annotation)loadBeanDefinitions:120, ConfigurationClassBeanDefinitionReader (org.springframework.context.annotation)processConfigBeanDefinitions:332, ConfigurationClassPostProcessor (org.springframework.context.annotation)postProcessBeanDefinitionRegistry:237, ConfigurationClassPostProcessor (org.springframework.context.annotation)invokeBeanDefinitionRegistryPostProcessors:280, PostProcessorRegistrationDelegate (org.springframework.context.support)invokeBeanFactoryPostProcessors:96, PostProcessorRegistrationDelegate (org.springframework.context.support)invokeBeanFactoryPostProcessors:707, AbstractApplicationContext (org.springframework.context.support)refresh:533, AbstractApplicationContext (org.springframework.context.support)refresh:755, SpringApplication (org.springframework.boot)refresh:747, SpringApplication (org.springframework.boot)refreshContext:402, SpringApplication (org.springframework.boot)run:312, SpringApplication (org.springframework.boot)loadContext:120, SpringBootContextLoader (org.springframework.boot.test.context)loadContextInternal:99, DefaultCacheAwareContextLoaderDelegate (org.springframework.test.context.cache)loadContext:124, DefaultCacheAwareContextLoaderDelegate (org.springframework.test.context.cache)getApplicationContext:123, DefaultTestContext (org.springframework.test.context.support)setUpRequestContextIfNecessary:190, ServletTestExecutionListener (org.springframework.test.context.web)prepareTestInstance:132, ServletTestExecutionListener (org.springframework.test.context.web)prepareTestInstance:244, TestContextManager (org.springframework.test.context)createTest:227, SpringJUnit4ClassRunner (org.springframework.test.context.junit4)runReflectiveCall:289, SpringJUnit4ClassRunner$1 (org.springframework.test.context.junit4)run:12, ReflectiveCallable (org.junit.internal.runners.model)methodBlock:291, SpringJUnit4ClassRunner (org.springframework.test.context.junit4)runChild:246, SpringJUnit4ClassRunner (org.springframework.test.context.junit4)runChild:97, SpringJUnit4ClassRunner (org.springframework.test.context.junit4)run:331, ParentRunner$4 (org.junit.runners)schedule:79, ParentRunner$1 (org.junit.runners)runChildren:329, ParentRunner (org.junit.runners)access$100:66, ParentRunner (org.junit.runners)evaluate:293, ParentRunner$2 (org.junit.runners)evaluate:61, RunBeforeTestClassCallbacks (org.springframework.test.context.junit4.statements)evaluate:70, RunAfterTestClassCallbacks (org.springframework.test.context.junit4.statements)evaluate:306, ParentRunner$3 (org.junit.runners)run:413, ParentRunner (org.junit.runners)run:190, SpringJUnit4ClassRunner (org.springframework.test.context.junit4)run:137, JUnitCore (org.junit.runner)startRunnerWithArgs:69, JUnit4IdeaTestRunner (com.intellij.junit4)startRunnerWithArgs:33, IdeaTestRunner$Repeater (com.intellij.rt.junit)prepareStreamsAndStart:235, JUnitStarter (com.intellij.rt.junit)main:54, JUnitStarter (com.intellij.rt.junit)loadBeanDefinitionsForConfigurationClass:148, ConfigurationClassBeanDefinitionReader (org.springframework.context.annotation) ...

April 25, 2022 · 4 min · jiezi

关于springboot:分布式配置系统Apollo如何实时更新配置的

引言记得咱们那时候刚开始学习Java的时候都只是一个单体我的项目,我的项目外面的配置根本都是写在我的项目外面的properties文件中,比方数据库配置啥的,各种逻辑开关,一旦这些配置批改了,还须要重启我的项目这批改才会失效。随着各种微服务的诞生,服务的拆分也越来越细,可能波及的服务成千上百,服务根本也是集群部署,这样再去一个一个我的项目批改配置,而后重启这显然是行不通的。所以分布式配置核心就诞生了,当初开源的分布式配置核心也挺多的比方:开源分布式配置核心有很多,比方spring-cloud/spring-cloud-config、淘宝/diamond、百度/disconf、携程/apollo、netflix/archaius、Qconf、XDiamond、nacos等等。咱们是不是很好奇配置核心如何做到实时更新并且告诉到客户端的这也是一个面试中常常会问到的题目。上面咱们就以apollo为例吧去剖析剖析它是如何实现的。为什么抉择Apollo来剖析列?因为当初的公司就在应用它作为配置核心。尽管Apollo是携程开源的,然而携程外部也不必它。 Apoll简介要去理解一个玩意,就要先会去应用它。它的应用基本上很简略。尽管应用简略不便,然而它的设计还是挺简单的,上面咱们看一个它官网提供的架构图,是不是挺简单的。通过上述架构图咱们能够看到ConfigService、AdminService、Client、Portal、 Meta Server、Eureka这几个模块,次要的还是后面四个模块Meta Server、Eureka这两个模块只是Apollo自身外部所须要的辅助模块,咱们临时能够不须要关注它。 ConfigService提供配置获取接口提供配置推送接口服务于Apollo客户端 AdminService提供配置管理接口提供配置批改公布接口服务于治理界面Portal Client为利用获取配置,反对实时更新通过MetaServer获取ConfigService的服务列表\应用客户端软负载SLB形式调用ConfigService Portal配置管理界面通过MetaServer获取AdminService的服务列表应用客户端软负载SLB形式调用AdminService Apoll更新配置介绍完了下面这些Apollo组成的模块回到正题,配置核心如何做到实时更新并且到客户端如何感知配置被更新了?看这个问题之前咱们先回顾下每到周末咱们去人气比拟旺的餐厅吃饭的时候流程是什么样的? 首先必定是现场取号,或者手机端取号。而后就是排队刷手机等着被叫号。中途你还会被动问一问还要等多久,服务员会通知你等着吧,你后面还有几桌。下面这个吃饭的例子怎么晓得到号了列?两种形式,一种使咱们我每隔一段时间而后被动去问下服务员,是否到号,没到号持续刷手机,如果到号间接进去吃饭,还有一种的话就是罗唆始终坐在那里刷手机我反正不赶时间,等着被告诉到号。同样的配置核心的更新是如何告诉到客户端列?是服务端主(configService)动告诉到客户端(client)通知它某某你的利用的配置被批改了,原来的值是啥被批改后的值是啥?还是说客户端(Client)每隔多久去问下服务端我的配置有没有被批改呀?如果是你你会怎么抉择列?你兴许会说我必定两种形式都要呀!小朋友才会做抉择? 客户端长链接获取配置更新告诉再回到咱们应用apollo的时候咱们利用外面引入的Apollo的Client在咱们利用启动的时候会有一个线程每隔5s向服务短发动一个http申请,不过这个http申请是不会立刻返回的。它是一个长链接如果配置没有被更新,这个申请会被阻塞挂起,这个实现挂起的形式是通过Spring的DeferredResult来实现的,如果对这个Spring的DeferredResult不是很理解的举荐看下这个文章《5种SpringMvc的异步解决形式你都理解吗?》挂起60s后会返回HTTP状态码为304给到客户端,如果再阻塞的过程中服务端配置有更新,这个Http申请会立马返回,并且把变动的nameSpace信息返回进来,并且返回的http的状态码是200。客户端失去状态码是200并且会依据nameSpace立刻去服务端拉取最新的配置。这里其实有一个问题,为什么不间接在长链接中返回变更后的后果,而是返回一个变更的告诉,须要客户端依据这个变更告诉立刻去拉取新的配置? 感兴趣的能够参考下这个issue :https://github.com/apolloconf...这样推送音讯就是有状态了,做不到幂等了,会带来很多问题。目前推送是单连贯走http的,所以问题可能不大,不过在设计上而言是有这个问题的,比方如果推送是走的tcp长连贯的话。另外,长轮询和推送之间也会有抵触,如果间断两次配置变动,就可能造成双写。还有一点,就是放弃逻辑的简略,目前的做法推送只负责做简略的告诉,不须要去计算客户端的配置应该是什么,因为计算逻辑挺简单的,须要思考集群,关联,灰度等,总而言之,就是在满足幂等性,实时性的根底上放弃设计的简略。客户端定时工作全量拉取配置这样是不是就是很完满了,客户端能够实时接管到配置的更新。然而客户端如果接管服务端的更新内容解决失败,比方服务异样或者空指针的时候。这时候咱们的客户端配置如果不重启是不是永远都不会被更新了。没关系这种状况apollo也帮你想到啦,你既然通知我更新失败,那我就本人每隔一段时间被动去把我所有的配置都拉到客服端,拉回客服端之后和客户端的缓存配置做比拟,如果统一间接完结,不统一就更新客户端的缓存,并且还会去异步更新本地文件。通过定时工作的补充,能够让配置达到最终的一致性。 客户端本地文件缓存配置被动轮询,和定时工作全量拉取配置是不是就十拿九稳呢?只有波及到分布式咱们就要思考到其余零碎的宕机,比方哪一天挖机间接把部署Apollo的机房的光纤给挖断了,这样整个配置服务间接挂了,这时候被动轮询以及定时工作都没法起到作用了。是不是拉取不了配置,整个咱们的客户端利用也要跟着受影响列,咱们的配置基本上是改变的频率也是比拟小的,即便咱们的配置核心挂掉了,咱们还有一份本地文件系统来兜底,这个文件目录默认是*/opt/data或C:\opt\data*, 所以即便配置核心挂了,对利用的影响也比拟小。因为它还会去读取本地文件来兜底。 小结到当初为止咱们应该晓得Apollo客户端是如何感知服务端配置更新了的把? 次要是通过客户端利用发动一个长连贯去Apollo ConfigServer端,如果Apollo ConfigServer端有配置更改会通知利用端有配置批改,让客户端立马去拉取全量的配置,并且把配置更新到本地缓存,并且还会异步去更新本地文件缓存。客户端还有一个默认5min执行一次的定时工作,去拉取全量的配置。拉回配置之后也是比照本地缓存和近程是否统一,如果不统一则更新本地过程缓存为近程的,同时还去异步更新下本地文件。 完结因为本人满腹经纶,难免会有纰漏,如果你发现了谬误的中央,还望留言给我指出来,我会对其加以修改。如果你感觉文章还不错,你的转发、分享、赞叹、点赞、留言就是对我最大的激励。感谢您的浏览,非常欢送并感谢您的关注。站在伟人的肩膀https://www.apolloconfig.com/...https://www.iocoder.cn/Apollo...

April 25, 2022 · 1 min · jiezi

关于springboot:SpringBoot集成消息队列

背景最近在对公司开发框架进行优化,框架内波及到多处入库的日志记录,例如登录日志/操作日志/拜访日志/业务执行日志,集成在业务代码中耦合度较高且占用业务操作执行工夫,所以筹备集成相干音讯队列进行代码解耦 计划布局现有的成熟音讯队列组件十分多,例如RabbitMQ,ActiveMQ,Kafka等,思考到业务并发量不高且框架曾经利用于多个我的项目安稳运行,筹备提供基于Redis的音讯队列和集成ActiveMQ两种计划,Redis音讯队列的益处是无需额定装置部署存量我的项目可安稳适度但音讯无奈长久化可能失落,ActiveMQ解决方案成熟能够保障音讯长久化然而须要施行人员额定把握操作部署 对立设计减少自定义配置指定音讯队列形式system: #音讯队列形式 redis/activemq messageChannel: redis定义音讯传输对立模型public class MessageModel { private Class<? extends IMessageReceiver> handleClazz; private String bodyContent; private Class bodyClass; private HashMap extraParam; public MessageModel(){ extraParam = new HashMap(); } public Class<? extends IMessageReceiver> getHandleClazz() { return handleClazz; } public void setHandleClazz(Class<? extends IMessageReceiver> handleClazz) { this.handleClazz = handleClazz; } public HashMap getExtraParam() { return extraParam; } public void setExtraParam(HashMap extraParam) { this.extraParam = extraParam; } public String getBodyContent() { return bodyContent; } public void setBodyContent(String bodyContent) { this.bodyContent = bodyContent; } public Class getBodyClass() { return bodyClass; } public void setBodyClass(Class bodyClass) { this.bodyClass = bodyClass; }}定义规范音讯解决接口public interface IMessageReceiver { void handleMessage(Object bodyObject, HashMap extraParam);}定义对立对外发送音讯工具类@Componentpublic class MessageUtil { @Autowired private SystemConfig systemConfig; @Autowired private RedisUtil redisUtil; @Autowired private JmsMessagingTemplate jmsMessagingTemplate; public void sendMessage(Object messageBody, Class<? extends IMessageReceiver> handleClass, HashMap<String,Object> extraParam) { MessageModel messageModel = new MessageModel(); messageModel.setHandleClazz(handleClass); messageModel.setBodyClass(messageBody.getClass()); messageModel.setBodyContent(JSON.toJSONString(messageBody)); if (extraParam != null) { for (String key:extraParam.keySet()) { messageModel.getExtraParam().put(key,extraParam.get(key)); } } if(systemConfig.getMessageChannel().equals("redis")){ redisUtil.sendMessage("message", JSON.toJSON(messageModel)); }else{ jmsMessagingTemplate.convertAndSend("message",JSON.toJSONString(messageModel)); } }}集成Redis音讯队列pom配置 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.0.1.RELEASE</version> </dependency>连贯配置spring: redis: host: localhost port: 6379 password:操作工具类 @Autowired private RedisTemplate redisTemplate; public void sendMessage(String channel, Object message) { redisTemplate.convertAndSend(channel, message); }音讯解决@Component@ConditionalOnProperty(name = "system.messageChannel", havingValue = "redis", matchIfMissing = true)public class RedisMessageReceiver { public void receiveMessage(String message) { MessageModel messageModel = JSON.parseObject(message, MessageModel.class); IMessageReceiver receiver = SpringBootBeanUtil.getBean(messageModel.getHandleClazz()); receiver.handleMessage(JSON.parseObject(messageModel.getBodyContent(), messageModel.getBodyClass()), messageModel.getExtraParam()); }}配置注册@Configurationpublic class MessageCenter { @Bean @ConditionalOnProperty(name = "system.messageChannel", havingValue = "redis", matchIfMissing = true) RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); // 能够增加多个 messageListener,配置不同的交换机 container.addMessageListener(listenerAdapter, new PatternTopic("message")); return container; } /** * 音讯监听器适配器,绑定音讯处理器,利用反射技术调用音讯处理器的业务办法 * * @param receiver * @return */ @Bean @ConditionalOnProperty(name = "system.messageChannel", havingValue = "redis", matchIfMissing = true) MessageListenerAdapter listenerAdapter(RedisMessageReceiver receiver) { return new MessageListenerAdapter(receiver, "receiveMessage"); }}集成ActiveMQ音讯队列pom配置 <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-pool</artifactId> <version>5.15.0</version> </dependency>留神:jdk1.8对应版本5.15.0 ...

April 23, 2022 · 2 min · jiezi

关于springboot:spring-boot-http接口单元测试运行流程分析

HandlerMappingIntrospector的initHandlerMappings()具体逻辑如下: private static List<HandlerMapping> initHandlerMappings(ApplicationContext applicationContext) { Map<String, HandlerMapping> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors( applicationContext, HandlerMapping.class, true, false); if (!beans.isEmpty()) { List<HandlerMapping> mappings = new ArrayList<>(beans.values()); AnnotationAwareOrderComparator.sort(mappings); return Collections.unmodifiableList(mappings); } return Collections.unmodifiableList(initFallback(applicationContext)); }能够看到beans的数量为8,此时HandlerMappingIntrospector.handlerMappings属性值曾经被赋值了。 private void filterAndRecordMetrics(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { Object handler; try { handler = getHandler(request);//1 } catch (Exception ex) { logger.debug("Unable to time request", ex); filterChain.doFilter(request, response); return; } // filterAndRecordMetrics(request, response, filterChain, handler); }第1处获取HandlerMethod;第2处,继续执行doFilter()办法,最终在MockFilterChain.doFilter()执行到DispatcherServlet.doDispatch(request, response);其中mappedHandler = getHandler(processedRequest);获取HandlerExecutionChain。 ...

April 21, 2022 · 1 min · jiezi

关于springboot:Spring-Boot内存泄露排查竟这么难

背景 为了更好地实现对我的项目的治理,咱们将组内一个我的项目迁徙到MDP框架(基于Spring Boot),随后咱们就发现零碎会频繁报出Swap区域使用量过高的异样。笔者被叫去帮忙查看起因,发现配置了4G堆内内存,然而理论应用的物理内存居然高达7G,的确不失常。JVM参数配置是“-XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+AlwaysPreTouch -XX:ReservedCodeCacheSize=128m -XX:InitialCodeCacheSize=128m, -Xss512k -Xmx4g -Xms4g,-XX:+UseG1GC -XX:G1HeapRegionSize=4M”,理论应用的物理内存如下图所示:排查过程 1.应用Java层面的工具定位内存区域(堆内内存、Code区域或者应用unsafe.allocateMemory和DirectByteBuffer申请的堆外内存) 笔者在我的项目中增加-XX:NativeMemoryTracking=detailJVM参数重启我的项目,应用命令jcmd pid VM.native_memory detail查看到的内存散布如下:发现命令显示的committed的内存小于物理内存,因为jcmd命令显示的内存蕴含堆内内存、Code区域、通过unsafe.allocateMemory和DirectByteBuffer申请的内存,然而不蕴含其余Native Code(C代码)申请的堆外内存。所以猜想是应用Native Code申请内存所导致的问题。 为了避免误判,笔者应用了pmap查看内存散布,发现大量的64M的地址;而这些地址空间不在jcmd命令所给出的地址空间外面,基本上就判定就是这些64M的内存所导致。2.应用零碎层面的工具定位堆外内存 因为笔者曾经基本上确定是Native Code所引起,而Java层面的工具不便于排查此类问题,只能应用零碎层面的工具去定位问题。 首先,应用了gperftools去定位问题 gperftools的应用办法能够参考gperftools,gperftools的监控如下:从上图能够看出:应用malloc申请的的内存最高到3G之后就开释了,之后始终维持在700M-800M。笔者第一反馈是:难道Native Code中没有应用malloc申请,间接应用mmap/brk申请的?(gperftools原理就应用动静链接的形式替换了操作系统默认的内存分配器(glibc)。) 而后,应用strace去追踪零碎调用 因为应用gperftools没有追踪到这些内存,于是间接应用命令“strace -f -e”brk,mmap,munmap” -p pid”追踪向OS申请内存申请,然而并没有发现有可疑内存申请。strace监控如下图所示:接着,应用GDB去dump可疑内存 因为应用strace没有追踪到可疑内存申请;于是想着看看内存中的状况。就是间接应用命令gdp -pid pid进入GDB之后,而后应用命令dump memory mem.bin startAddress endAddressdump内存,其中startAddress和endAddress能够从/proc/pid/smaps中查找。而后应用strings mem.bin查看dump的内容,如下:从内容上来看,像是解压后的JAR包信息。读取JAR包信息应该是在我的项目启动的时候,那么在我的项目启动之后应用strace作用就不是很大了。所以应该在我的项目启动的时候应用strace,而不是启动实现之后。 再次,我的项目启动时应用strace去追踪零碎调用 我的项目启动应用strace追踪零碎调用,发现的确申请了很多64M的内存空间,截图如下:应用该mmap申请的地址空间在pmap对应如下:最初,应用jstack去查看对应的线程 因为strace命令中曾经显示申请内存的线程ID。间接应用命令jstack pid去查看线程栈,找到对应的线程栈(留神10进制和16进制转换)如下:这里基本上就能够看出问题来了:MCC(美团对立配置核心)应用了Reflections进行扫包,底层应用了Spring Boot去加载JAR。因为解压JAR应用Inflater类,须要用到堆外内存,而后应用Btrace去追踪这个类,栈如下:而后查看应用MCC的中央,发现没有配置扫包门路,默认是扫描所有的包。于是批改代码,配置扫包门路,公布上线后内存问题解决。 3.为什么堆外内存没有开释掉呢? 尽管问题曾经解决了,然而有几个疑难: 为什么应用旧的框架没有问题?为什么堆外内存没有开释?为什么内存大小都是64M,JAR大小不可能这么大,而且都是一样大?为什么gperftools最终显示应用的的内存大小是700M左右,解压包真的没有应用malloc申请内存吗?带着疑难,笔者间接看了一下Spring Boot Loader那一块的源码。发现Spring Boot对Java JDK的InflaterInputStream进行了包装并且应用了Inflater,而Inflater自身用于解压JAR包的须要用到堆外内存。而包装之后的类ZipInflaterInputStream没有开释Inflater持有的堆外内存。于是笔者认为找到了起因,立马向Spring Boot社区反馈了这个bug。然而反馈之后,笔者就发现Inflater这个对象自身实现了finalize办法,在这个办法中有调用开释堆外内存的逻辑。也就是说Spring Boot依赖于GC开释堆外内存。 笔者应用jmap查看堆内对象时,发现曾经基本上没有Inflater这个对象了。于是就狐疑GC的时候,没有调用finalize。带着这样的狐疑,笔者把Inflater进行包装在Spring Boot Loader外面替换成本人包装的Inflater,在finalize进行打点监控,后果finalize办法的确被调用了。于是笔者又去看了Inflater对应的C代码,发现初始化的应用了malloc申请内存,end的时候也调用了free去开释内存。 此刻,笔者只能狐疑free的时候没有真正开释内存,便把Spring Boot包装的InflaterInputStream替换成Java JDK自带的,发现替换之后,内存问题也得以解决了。 这时,再返过去看gperftools的内存散布状况,发现应用Spring Boot时,内存应用始终在减少,忽然某个点内存应用降落了好多(使用量间接由3G降为700M左右)。这个点应该就是GC引起的,内存应该开释了,然而在操作系统层面并没有看到内存变动,那是不是没有开释到操作系统,被内存分配器持有了呢? 持续探索,发现零碎默认的内存分配器(glibc 2.12版本)和应用gperftools内存地址散布差异很显著,2.5G地址应用smaps发现它是属于Native Stack。内存地址散布如下:到此,基本上能够确定是内存分配器在捣鬼;搜寻了一下glibc 64M,发现glibc从2.11开始对每个线程引入内存池(64位机器大小就是64M内存),原文如下:依照文中所说去批改MALLOC_ARENA_MAX环境变量,发现没什么成果。查看tcmalloc(gperftools应用的内存分配器)也应用了内存池形式。 为了验证是内存池搞的鬼,笔者就简略写个不带内存池的内存分配器。应用命令gcc zjbmalloc.c -fPIC -shared -o zjbmalloc.so生成动静库,而后应用export LD_PRELOAD=zjbmalloc.so替换掉glibc的内存分配器。其中代码Demo如下: ...

April 20, 2022 · 2 min · jiezi

关于springboot:Redis官方可视化工具RedisInsight

最近逛了一下Redis官方网站,发现Redis不仅推出了很多新个性,而且还公布了一款可视化工具RedisInsight。试用了一下感觉十分不错,最要害的是能反对RedisJSON之类的新个性,这是第三方工具无法比拟的。 RedisInsight简介RedisInsight是Redis官网出品的可视化管理工具,可用于设计、开发、优化你的Redis利用。反对深色和浅色两种主题,界面十分炫酷!可反对String、Hash、Set、List、JSON等多种数据类型的治理,同时反对近程应用CLI性能,性能十分弱小!上面是RedisInsight的一张应用效果图,颜值是相当的不错! RedisMod简介Redis通过多年倒退,早已不仅仅是一个内存数据库了。有了RedisMod的反对,Redis的性能将变得十分弱小。RedisMod中蕴含了如下加强模块: RediSearch:一个功能齐全的搜索引擎;RedisJSON:对JSON类型的原生反对;RedisTimeSeries:时序数据库反对;RedisGraph:图数据库反对;RedisBloom:概率性数据的原生反对;RedisGears:可编程的数据处理;RedisAI:机器学习的实时模型治理和部署。装置首先咱们将应用Docker来装置Redis,留神下载Redis的齐全体版本RedisMod,它是内置了所有模块的增强版Redis!应用如下命令下载RedisMod的镜像,如下: docker pull redislabs/redismod:preview而后,在容器中运行RedisMod服务。 docker run -p 6379:6379 --name redismod \-v /mydata/redismod/data:/data \-d redislabs/redismod:preview应用根本应用首先下载RedisInsight的安装包,下载地址:https://redis.com/redis-enterprise/redis-insight/。 下载实现后间接装置即可,装置实现后在主界面抉择增加Redis数据库。抉择手动增加数据库,输出Redis服务连贯信息即可;关上连贯后即可治理Redis,右上角会显示曾经装置的Redis加强模块;接下来咱们就能够通过RedisInsight在Redis中增加键值对数据了,比方增加String类型键值对;增加Hash类型,编辑的时候能够单个属性编辑;增加JSON类型,装置RedisJSON模块后可反对;对原生JSON类型,不仅反对高亮预览,还能反对新增、编辑和删除单个属性; CLI如果RedisInsight的图形化界面性能满足不了你的话,还能够试试它的CLI性能,点击左下角CLI标签即可关上; 贴心的Redis官网怕你记不住命令,还增加了Command Helper这个查找命令文档的性能,比方咱们能够搜寻下hget这个命令的用法。 Profiler通过Profiler性能,咱们能够查看Redis的命令执行日志,比方咱们应用RedisInsight增加一个叫testKey的键值对,Profiler将显示如下日志。 可视化监控RedisInsight的Redis监控性能比较简单,集体比拟喜爱应用Grafana来监控Redis,Grafana的具体应用能够参考Grafana应用教程 。 装置Grafana首先下载Grafana的Docker镜像: docker pull grafana/grafana下载实现后运行Grafana; docker run -p 3000:3000 --name grafana \-d grafana/grafana接下来下载Prometheus的Docker镜像; docker pull prom/prometheus在/mydata/prometheus/目录下创立Prometheus的配置文件prometheus.yml: global: scrape_interval: 5s运行Prometheus,把宿主机中的配置文件prometheus.yml挂载到容器中去; docker run -p 9090:9090 --name prometheus \-v /mydata/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml \-d prom/prometheus进入grafana容器并装置redis-datasource插件,装置实现后须要重启grafana服务。 docker exec -it grafana /bin/bashgrafana-cli plugins install redis-datasource应用连贯到redismod须要应用到它的容器IP地址,应用如下命令查看redismod容器的IP地址;在Grafana中配置好Redis数据源,应用admin:admin账户登录,拜访地址;http://192.168.3.105:3000/ 配置Redis地址信息,留神应用redismod的容器IP地址; 关上Dashboard抉择Redis; 接下来就能够看到一个十分欠缺的Redis监控仪表盘了,根本能满足Redis的监控需要。 总结RedisInsight不愧是官网出品的可视化工具,感觉是目前用起来体验最好的Redis工具了!特地是对Redis新个性的反对,其余工具是无法比拟的!不过对Redis的监控性能的确有点简略,还是得用业余的监控工具Grafana来监控Redis!

April 19, 2022 · 1 min · jiezi

关于springboot:SpringBoot集成knife4j

前言我的项目api编写有文档然而调试麻烦,须要借助postman/apipost等第三方工具,须要在开发框架中内置接口治理及调试性能减少开发便捷性 pom配置阐明,框架应用springboot版本为2.0.0.RELEASE <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>2.0.3</version> </dependency>拦截器配置在我的项目中个别会存在鉴权拦截器,须要将knife4j相干资源放行 anonymousAccessList.add("/swagger-resources"); anonymousAccessList.add("/swagger-resources/configuration/ui"); anonymousAccessList.add("/v2/api-docs"); anonymousAccessList.add("/v2/api-docs-ext"); anonymousAccessList.add("/doc.html"); anonymousAccessList.add("/webjars/*"); anonymousAccessList.add("/favicon.ico");Config配置@Configuration@EnableSwagger2@EnableKnife4j@Import(BeanValidatorPluginsConfiguration.class)public class SwaggerConfiguration { @Value("${spring.profiles.active}") private String active; @Bean(value = "frameAPI") @Conditional({SwaggerProjectCondition.class}) public Docket frameAPI() { Docket docket = new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo("xxx", "xxx")) //分组名称 .groupName("xxx") .select() //这里指定Controller扫描包门路 .apis(RequestHandlerSelectors.basePackage("com.xxx.xxx")) .paths(PathSelectors.any()) .build(); docket.enable(!active.equals("pro")); return docket; } private ApiInfo apiInfo(String appTag, String docName) { return new ApiInfoBuilder() .title(appTag + " api") .description(docName) .contact("admin") .version("1.0") .build(); }}注:因为应用knife4j版本不是最新,所以通过docket.enable代码配置的形式管制生产环境敞开文档资源的拜访

April 17, 2022 · 1 min · jiezi

关于springboot:micamqtt-130-发布拆分-client-和-server-的-spring-boot-starter

一、简介mica-mqtt 基于 t-io 实现的简略、低提早、高性能 的 mqtt 物联网开源组件。 mica-mqtt 更加易于集成到已有服务和二次开发,升高自研物联网平台开发成本。 二、性能反对 MQTT v3.1、v3.1.1 以及 v5.0 协定。反对 websocket mqtt 子协定(反对 mqtt.js)。反对 http rest api,http api 文档详见。反对 MQTT client 客户端。反对 MQTT server 服务端。反对 MQTT 遗嘱音讯。反对 MQTT 保留音讯。反对自定义音讯(mq)解决转发实现集群。MQTT 客户端 阿里云 mqtt 连贯 demo。反对 GraalVM 编译老本机可执行程序。反对 Spring boot 我的项目疾速接入(mica-mqtt-spring-boot-starter)。mica-mqtt-spring-boot-starter 反对对接 Prometheus + Grafana。基于 redis pub/sub 实现集群,详见 mica-mqtt-broker 模块。三、应用场景物联网(云端 mqtt broker)物联网(边缘端音讯通信)群组类 IM音讯推送简略、易用的 mqtt client 客户端四、更新记录v1.3.0 - 2022-04-17✨ mica-mqtt mqtt-server 简化,默认多设施能够间接相互订阅和解决音讯。✨ mica-mqtt server、client 增加 tioConfigCustomize 办法,不便更大程度的自定义 TioConfig。✨ 拆分 mica-mqtt-client-spring-boot-starter 和 mica-mqtt-server-spring-boot-starter gitee #I4OTC5✨ mica-mqtt-client-spring-boot-example 增加重连动静更新 clientId、username、password 示例。✨ mica-mqtt server 增加依据踢出指定 clientId 的 http api 接口。✨ mica-mqtt server IMqttConnectStatusListener api 调整,增加 username 字段。✨ mica-mqtt server IMqttMessageListener 不再强制要求实现。✨ 应用 netty IntObjectHashMap 优化默认 session 存储。✨ 增加 github action,用于提交后主动构建 SNAPSHOT 版本。✨ 示例我的项目拆分到 example 目录,mica-mqtt client、server starter 拆分到 starter 目录。⬆️ 依赖降级.重点阐明此版本拆分出 mica-mqtt-client-spring-boot-starter 和 mica-mqtt-server-spring-boot-starter。 ...

April 17, 2022 · 1 min · jiezi

关于springboot:Spring-Boot学习三自动装配

@SpringBootApplication//设置以后注解能够标记在哪里@Target(ElementType.TYPE) //当注解标注的类编译以什么形式保留 RUNTIME会被JVM加载 @Retention(RetentionPolicy.RUNTIME) //java doc会生成注解信息@Documented //是否会被继承 @Inherited//标注在某个类上,示意这是一个SPring Boot的配置类@SpringBootConfiguration//配置类上来标注这个注解@Configuration//开启主动配置性能,会帮咱们主动去加载@EnableAutoConfiguration//扫描包 相当于在spring.xml 配置中<context:comonent-scan> //然而并没有指定basepackage,如果没有指定spring底层会主动扫描以后配置类所在的包@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })//spring boot对外提供的扩大类,能够供咱们去依照咱们的形式进行排除TypeExcludeFilter//排除所有配置类并且是主动配置类外面的其中一个AutoConfigurationExcludeFilter@EnableAutoConfiguration@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited//将以后配置类所在的包保留在BasePackages的Bean中。供Spring外部应用@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)

April 14, 2022 · 1 min · jiezi

关于springboot:盘古开发框架开发架构模式选型对比

「盘古开发框架」是一套轻量灵便、成熟牢靠的工业级散布式微服务开发和治理框架(兼容垂直单体分层架构)。基于 Apache-2.0 协定开源公布,且是收费的。咱们心愿不仅是开源的受益者,也能成为开源的贡献者,与开源社区一起「共建共享开源生态」。盘古开发框架不会绑定用户到一个固定的开发范式和架构上,而是反对随便组合、主动拆卸、灵便插拔。 既能构建大并发高可用的散布式微服务架构也能搭建玲珑的垂直单体分层架构。 写在后面软件架构的实质是一种在特定资源背景下折中均衡后谋求业务增长的一门艺术。决定技术开发架构选型的因素很多。这里,咱们对不同开发架构模式进行主观比拟,心愿对大家在技术架构选型时能有所帮忙。 单体分层架构 VS 微服务分布式架构-单体分层架构微服务分布式架构开发开发测试流程简略开发测试流程绝对简单部署运维单机部署或集群部署(简略)、运维成本低分布式部署(略难)、运维老本高团队人员团队围绕一个利用开发、开发人员能力要求低多任务团队合作简略、开发人员能力要求略高其它扩展性弱、可靠性低、技术创新能力弱、企业对代码等数字资产管控能力弱扩展性强、可靠性高、技术创新能力强、企业对代码等数字资产管控能力高上述指标比照均为绝对后果,仅供参考。在特定我的项目资源、团队背景、业务场景等环境下,相干指标的高下强弱比照是会有偏差甚至反转的。盘古开发架构选型倡议如下是从不同维度简略粗犷的以定量或定性的角度给出了一些选型倡议,论断是孤立的脱离实际的,仅供参考。采纳什么样的架构开发模式不能一概而论,须要大家综合当下理论状况酌情抉择。 -单体分层架构微服务分布式架构开发人员 < 5✔ 研发估算 < 100 w✔ 用户数较小的治理类零碎✔ 面向C端的(挪动)互联网利用 ✔多任务多小组合作 ✔有专职运维人员 ✔谋求可维护性和扩展性 ✔谋求技术团队长期收益 & 增长 ✔甲方企业自建的技术团队 ✔我的项目外包性质的守业公司(乙方)✔ 下一步持续浏览其它章节获取你想要的答案或通过咱们的 开发者社区 寻求更多帮忙。

April 11, 2022 · 1 min · jiezi

关于springboot:Spring-Boot学习二注入

Spring properties配置官网https://docs.spring.io/spring... 通过注解绑定application.yml单个配对能够通过@Value(${user.username})private String username;@ConfigurationProperties 作用 罕用与bean属性和yml配置文件的绑定prefix 能够指定配置文件某一个节点,该节点中的子节点将主动和属性进行绑定涣散绑定:(USERNAME、userName、user_name、user-name)以上4中命名是能够主动绑定bean属性 <!-- 会生成META-INF 元数据 用于提供idea主动提醒配置文件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <!-- 依赖不会流传 --> <optional>true</optional> </dependency>@Validated 反对jsr-303数据校验须要应用还须要增加该依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> application.yml文件user: userName: "LLL"# 汇合 list、set# 写法一 hobbies: - 1 - 2 - 3# 写法二 hobbies: [1,2,3]# 汇合 map# 写法一 girl-friend: 13 : 陈奕迅 14 : 张国荣# 写法二 girl-friend: {13: 陈奕迅,14: 张国荣}# 对象 address: id: 1 desc: 北京# 拼接 援用值 address: id: 1 desc: ${userName}北京# 随机生成 age: ${random.int}# ${random.value} # ${random.int}# ${random.long}# ${random.uuid}# ${random.int(10)} 几位数# ${random.int[1024,65536]} 范畴1024-65536文件绑定@Data@Component@ConfigurationProperties(prefix="user")// 绑定到某个properties 只容许是properties文件 data为文件夹@PropertySource("classpath:/data/user.properties")public class User { @NotNull private String username; private Integer age; private Date birthday; private List<String> hobbies; private Map<Integer,String> girlFriend; private Address address;}

April 10, 2022 · 1 min · jiezi

关于springboot:SpringBoot异步任务获取HttpServletRequest

前言在应用框架日常开发中须要在controller中进行一些异步操作缩小申请工夫,然而发现在应用@Anysc注解后会呈现Request对象无奈获取的状况,本文就此状况给出残缺的解决方案 起因剖析@Anysc注解会开启一个新的线程,主线程的Request和子线程是不共享的,所以获取为null在应用springboot的自定带的线程共享后,代码如下,Request不为null,然而偶发的其中body/head/urlparam内容呈现获取不到的状况,是因为异步工作在未执行结束的状况下,主线程曾经返回,拷贝共享的Request对象数据被清空ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();//设置子线程共享RequestContextHolder.setRequestAttributes(servletRequestAttributes, true);HttpServletRequest request = servletRequestAttributes.getRequest();解决方案前置条件启动类增加@EnableAsync注解标记@Async的异步办法不能和调用者在同一个class中pom配置 <!-- 阿里线程共享 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>transmittable-thread-local</artifactId> <version>2.11.0</version> </dependency>requrest共享通过TransmittableThreadLocal对象进行线程对象共享 public class CommonUtil { public static TransmittableThreadLocal<HttpServletRequest> requestTransmittableThreadLocal = new TransmittableThreadLocal<HttpServletRequest>(); public static void shareRequest(HttpServletRequest request){ requestTransmittableThreadLocal.set(request); } public static HttpServletRequest getRequest(){ HttpServletRequest request = requestTransmittableThreadLocal.get(); if(request!=null){ return requestTransmittableThreadLocal.get(); }else{ ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if(requestAttributes!=null){ return requestAttributes.getRequest(); }else{ return null; } } } public static void remove(){ requestTransmittableThreadLocal.remove(); }}注:零碎中所有Request获取须要对立从CommonUtil指定起源,例如token鉴权等 自定义request过滤器通过自定义过滤器对Request的内容进行备份保留,主线程完结时Request革除完结不会影响到子线程的相应参数的获取,也实用于减少拦截器/过滤器后body参数无奈反复获取的问题。须要留神的是对header参数解决时key要疏忽大小写 ...

April 9, 2022 · 2 min · jiezi

关于springboot:SpringBoot-2x-实战仿B站高性能后端项目无密分享

SpringBoot 2.x 实战仿B站高性能后端我的项目-无密分享超清原画 残缺无密 包含所有视频课件以及源码 点击下崽:网盘链接基于Node.js的ORM框架 Prisma的上手使用 Node.js作为咱们前端的一项技术,大多数工夫是作为一个Javascript的运行环境而存在。然而其优良的异步操作以及非阻塞式的程序运行形式,也让Node.js能够同时并发处理数千个连接。前端工程师可能用很低的学习成本来使用它实现罕用的服务端代码。 ORMORM:对象关系映射(Object Relational Mapping)是一种程序设计技术。简略来说ORM可能将咱们的底层数据库的各种操作进行肯定的封装,咱们就可能通过更加熟悉的开发语言来书写对应的数据库命令,ORM则可能将这些数据库操作命令转换为对应的SQL语句。 Prisma下一代 Node.js、TypeScript、Go 的数据库 ORM Prisma是一个开源的数据库工具链我的项目,帮助开发人员更快地构建应用程序并缩小谬误,反对PostgreSQL、MySQL、MongoDB、SQL Server和SQLite。 如果想要了解一门技术的用法,那么咱们则需要通过实际的上手使用它来进行一点点的开发。 首先咱们需要初始化一个我的项目 mkdir prisma-demo # 创建一个目录cd prisma-demo # 通过命令行来进入该我的项目目录npm init -y # 将我的项目进行初始化{ "name": "prisma-demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo "Error: no test specified" && exit 1"}, "keywords": [], "author": "", "license": "ISC"}复制代码而后咱们将本次所需要使用的prisma进行安装一下 npm install prisma -D # 安装prisma复制代码安装实现后,咱们可能通过npx prisma init -h命令来查看prisma相干的命令帮助信息 Setup a new Prisma projectUsage $ prisma init [options]Options ...

April 7, 2022 · 3 min · jiezi

关于springboot:Spring-Boot学习一父子项目图标配置文件

1、创立父子我的项目 1、须要在父我的项目pom.xml文件增加 <packaging>pom</packaging>2、须要在子项目中更改 <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.6</version> <relativePath/>更改为父我的项目的 <groupId>com.jc</groupId> <artifactId>springboot_parent</artifactId> <version>0.0.1-SNAPSHOT</version> 子项目中替换 2、spring boot图标替换springboot图标生成器:https://www.bootschool.net/ascii把banner.txt文件放在resources配置包下(会主动读取banner.txt) 能够设置敞开图标SpringApplication启动类配置@SpringBootApplicationpublic class Springboot01Application { public static void main(String[] args) { SpringApplication app = new SpringApplication(Springboot01Application.class);// app.setBannerMode(Banner.Mode.OFF); //能够设置敞开springboot横幅 app.run(args); }}3、配置文件# 1、application.properties K/v构造# 端口号server.port=1313# 前缀:localhost:1313/lll/helloserver.servlet.context-path=/lll# 2、application.yml 树形构造server: prot: 1313application.yaml配置文件的加载程序 优先读取,后读取的补充(父配置优先->子配置) <includes> <include>**/application*.yml</include> <include>**/application*.yaml</include> <include>**/application*.properties</include> </includes>4、多个profile文件Spring官网语法:application-xxx.properties(.yaml/yml)spring.profiles.active=dev 不要混合应用配置文件(yml、yaml、properties),保持只是用其中之一。

April 7, 2022 · 1 min · jiezi

关于springboot:4-种-SpringBoot-项目鉴权方式

传统 AOP 对于这种需要,首先想到的当然是 Spring-boot 提供的 AOP 接口,只须要在 Controller 办法前增加切点,而后再对切点进行解决即可。 实现 其应用步骤如下: 应用 @Aspect 申明一下切面类 WhitelistAspect; 在切面类内增加一个切点 whitelistPointcut(),为了实现此切点灵便可拆卸的能力,这里不应用 execution 全副拦挡,而是增加一个注解 @Whitelist,被注解的办法才会校验白名单。 在切面类中应用 spring 的 AOP 注解 @Before 申明一个告诉办法 checkWhitelist() 在 Controller 办法被执行之前校验白名单。 切面类伪代码如下: @Aspect public class WhitelistAspect { @Before(value = "whitelistPointcut() && @annotation(whitelist)") public void checkAppkeyWhitelist(JoinPoint joinPoint, Whitelist whitelist) { checkWhitelist(); // 可应用 joinPoint.getArgs() 获取Controller办法的参数 // 能够应用 whitelist 变量获取注解参数 } @Pointcut("@annotation(com.zhenbianshu.Whitelist)") public void whitelistPointCut() { } } 在 Controller 办法上增加 @Whitelist 注解实现性能。 ...

April 7, 2022 · 3 min · jiezi

关于springboot:springboot约定优于配置的体现

springboot约定优于配置的体现一、Maven的目录构造:默认有resources文件夹寄存配置文件默认打包形式为jar 二、默认的配置文件:application.properties 或 application.yml 文件 三、默认通过 spring.profiles.active 属性来决定运行环境时的配置文件。 四、EnableAutoConfiguration 默认对于依赖的 starter 进行主动装载。 五、spring-boot-start-web 中默认蕴含 spring-mvc 相干依赖以及内置的 tomcat 容器,使得构建一个 web 利用更加简略。

April 6, 2022 · 1 min · jiezi

关于springboot:Spring-Order-注解你可能理解错了

1. 问题形容最近在梳理我的项目中的基础设施模块,心愿将主动扫描(@ComponentScan)的形式,改为基于 @Configuration 的形式,这样在编写测试类的时候,可能有抉择的对基础设施相干的 Bean 进行拆卸。通过这样的梳理和思考,可能晋升模块的内聚性。然而,在操作的过程中基于理论状况,认为某些 Bean 的实例化有先后顺序,因而想当然的认为可能通过 @Order 注解(或者 Ordered 接口)来实现 Bean 实例化的先后顺序。其实不然。 2. 问题剖析咱们定义了如下 3 个 Bean。别离实现 Ordered 接口,并别离返回 3、2、1。按预期的成果,应该值越小,越先初始化。 @Slf4j@Componentpublic class AOrderBean implements Ordered { public AOrderBean() { log.info("init AOrderBean"); } @Override public int getOrder() { return 3; }}@Slf4j@Componentpublic class BOrderBean implements Ordered { public BOrderBean() { log.info("init BOrderBean"); } @Override public int getOrder() { return 2; }}@Slf4j@Componentpublic class COrderBean implements Ordered { public COrderBean() { log.info("init COrderBean"); } @Override public int getOrder() { return 1; }}程序运行后果: ...

March 29, 2022 · 1 min · jiezi

关于springboot:SpringBoot-ES基本项目搭建实例

【搜寻系列】ES根本我的项目搭建之前始终没有写ES相干的博文,当初开始补课,预计5-6篇博文将es的应用姿态展现给各位小伙伴;本文将作为es联合springboot的第一篇博文,根本我的项目环境搭建 <!-- more --> I. 我的项目搭建1. 我的项目依赖本我的项目借助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA进行开发 开一个web服务用于测试 <dependencies> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency></dependencies>2. 配置信息配置文件application.yml,留神上面的配置信息,上面采纳的是由咱们本人来解析配置的形式 elasticsearch: host: localhost port: 9200 user: elastic pwd: test123 connTimeout: 3000 socketTimeout: 5000 connectionRequestTimeout: 500阐明 下面配置介绍的是一种偏根底的es文档操作姿态,相比拟于封装得更好的spring-boot-starter-data-elasticsearch,应用更加灵便 II. SpringBoot联合ES应用1. RestHighLevelClient 初始化接下来咱们基于RestHighLevelClient来操作es,首先第一步就是须要初始化这实例 @Getter@Configurationpublic class ElasticsearchConfiguration { @Value("${elasticsearch.host}") private String host; @Value("${elasticsearch.port}") private int port; @Value("${elasticsearch.connTimeout}") private int connTimeout; @Value("${elasticsearch.socketTimeout}") private int socketTimeout; @Value("${elasticsearch.connectionRequestTimeout}") private int connectionRequestTimeout; @Value("${elasticsearch.user}") private String user; @Value("${elasticsearch.pwd}") private String pwd; @Bean(destroyMethod = "close", name = "client") public RestHighLevelClient initRestClient() { RestClientBuilder builder = RestClient.builder(new HttpHost(host, port)) .setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder .setConnectTimeout(connTimeout) .setSocketTimeout(socketTimeout) .setConnectionRequestTimeout(connectionRequestTimeout)); return new RestHighLevelClient(builder); }}留神下面的实现,用户名 + 明码并没有应用,当es设置了用户名、明码之后,是通过每次申请时,在申请头基于Basic Auth形式进行身份验证的;前面会介绍到 ...

March 29, 2022 · 1 min · jiezi

关于springboot:Spring-Cache缓存框架

一、序言Spring Cache是Spring体系下标准化缓存框架。Spring Cache有如下劣势: 缓存种类多反对缓存种类多,常见缓存Redis、EhCache、Caffeine均反对。它们之间既能独立应用,也能组合应用。 平滑迁徙Spring外部反对的缓存,可实现无缝平滑迁徙,无需批改业务逻辑。注解缓存的实现依赖于动静代理。 大多数状况下应用的是注解版、多数状况下也能应用编程版。注解版与业务代码高度解藕,因其依靠动静代理技术实现,应用场景上有肯定的限度。编程版嵌入业务代码,代码程序执行,无前置应用条件。 二、基本概念(一)外围概念一个利用能够有多个缓存管理器,每个缓存管理器能够有多个缓存,每个缓存能够存储多条记录。 1、缓存管理器缓存的存储介质不同、缓存连贯不同的数据库、缓存值序列化等由缓存管理器配置。缓存管理器有主次之分,默认状况下应用主(首要)缓存管理器。 当服务内只有一个CacheManager时,默认应用此缓存管理器;当超过一个缓存管理器时,须要应用Primary注解指定默认缓存管理器。 2、缓存Cache是一组配置雷同缓存的汇合,能够了解为命名空间,Spring Cache体系下的缓存生命工夫是以Cache为单位的,不反对以Key为单位设置生存工夫。不同的业务对应不同的缓存配置,应在缓存处予以辨别。 CacheName应具备显著的业务区分度以及过期工夫区分度,并且以全局常量的形式提供,采取集中化治理的形式,禁止采纳魔术变量的形式指定CacheName。 (二)补充内容一般来说缓存的Key与Value均是String类型,特地是Value通常序列化成JSON串。 三、注解版用于基于注解的形式来治理缓存数据。注解缓存有如下劣势: 高度解藕应用注解来实现缓存,与业务高度解藕。 灵便治理通过全局配置,不批改缓存逻辑,可实现如下成果: 开发环境下,可禁用缓存,将流量打入数据库,尽早的裸露可能存在的性能瓶颈;测试环境开启缓存,进行压力测试等。 (一)动静代理Spring Cache缓存注解版的原理以及缓存配置失败的典型案例。 1、CGLib动静代理缓存的实现底层技术支持是CGLib动静代理,在指标办法调用前、后别离追加相应的缓存操作,以达到增加缓存、更新缓存、删除缓存的操作。 如果注解缓存配置未失效,查看指标调用办法是否被动静代理。 2、配置生效配置生效是指只管配置了缓存注解,但缓存依然未失效。 final类与final办法final类与final办法不满足CGLib动静代理的条件,因而缓存配置会生效。 外部调用应用依赖注入的形式调用配置缓存的办法失效,办法间外部调用不失效。 非public办法非public办法配置缓存不失效。 (二)罕用注解1、配置注解(1)EnableCaching 标注于SpringBoot利用启动类上,增加此注解示意开启Spring Cache缓存;移除示意敞开缓存。如果在全局配置文件中增加如下配置,即便在启动类上标注EnableCaching注解,Spring Cache缓存而后是敞开状态。 spring: cache: type: none如果利用中自定义独立于Spring容器的缓存,则不受此配置影响。 (2)CacheConfig 标注于类上,更具体的说是标注于业务服务类上。对立配置如下参数信息: 参数含意应用阐明cacheManager缓存管理器缺省指首要的CacheManagercacheNames缓存名 keyGeneratorkey值生成器 在类上对立进行配置,类下的办法主动继承相应的配置。 2、缓存注解(1)Cacheable 增加缓存的外围注解,分两种状况:一是对应key值未有缓存数据,先执行办法,而后依据condition和unless条件决定是否增加缓存;二是对应key值已有缓存,不执行办法体,间接返回数据。 参数keyGenerator与key是互斥的,当key存在时keyGenerator配置主动生效。 根底参数参数含意应用阐明cacheManager缓存管理器缺省指首要的CacheManagercacheNames缓存名 keyGeneratorkey值生成器 keykey值 高级参数参数含意默认值应用阐明condition缓存条件 批示满足条件方执行缓存操作,个别应用参数作为条件unless否定缓存 当条件为 true ,办法的返回值不会被缓存sync同步状态false示意将办法执行后果以何种形式存入缓存(2)CachePut 更新缓存注解。不论对应key值是否有缓存数据,都执行。 根底参数参数含意应用阐明cacheManager缓存管理器缺省指首要的CacheManagercacheNames缓存名 keyGeneratorkey值生成器 keykey值 高级参数参数含意应用阐明condition缓存条件批示满足条件方执行缓存操作,个别应用参数作为条件unless否定缓存当条件为 true ,办法的返回值不会被缓存(3)CacheEvict 被动革除缓存注解。 根底参数参数含意应用阐明cacheManager缓存管理器缺省指首要的CacheManagercacheNames缓存名 keyGeneratorkey值生成器 keykey值 高级参数参数含意默认值应用阐明condition缓存条件 批示满足条件方执行缓存操作,个别应用参数作为条件allEntries所有缓存false示意是否清空以后CacheName对应的所有缓存beforeInvocation调用前false示意是否在办法调用前清空缓存3、KeyGenerator默认状况下应用SimpleKeyGenerator键值生成器,当不指定key值时,依据生成器规定,将办法参数转化为缓存Key值。 喜爱本文点个♥️赞♥️反对一下,如有须要,可通过微信dream4s与我分割。相干源码在GitHub,视频解说在B站,本文珍藏在博客天地。

March 29, 2022 · 1 min · jiezi

关于springboot:springboot单元测试Test没有绿色三角标识启动箭头

author: Nathanniedate: 2022-3-26-23:19 问题背景学习mybatis plus,应用Mapper接口阶段中,在springboot我的项目中的测试包中测试接口,应用@Test注解,定义的测试方法下面没有三角绿色启动标识。 异样内容图-失常状况下,测试方法显示三角绿色启动标识 图-异常情况下,测试方法不显示三角绿色启动标识 问题剖析可能起因 测试方法修饰符不是public测试类修饰符不是public问题解决最终起因是测试类的拜访修饰符没有设置为public,导致是默认修饰符,只须要增加public修饰符即可 import org.junit.Test;// ...@SpringBootTestpublic class PlusApplicationTests { }注意事项: spring-boot-starter-test的依赖包中应该蕴含了junit的依赖,有可能是版本抵触造成的,能够尝试着去掉Junit的依赖试试。 https://ask.csdn.net/question...因为以后应用的是springboot我的项目,无需手动增加Junit包,应用spring-boot-starter-test中的junit依赖即可 相干参考https://blog.csdn.net/escFAJ/...办法中运行小箭头未呈现https://ask.csdn.net/question... SpringBoot测试包无奈应用的问题?

March 26, 2022 · 1 min · jiezi

关于springboot:SpringBoot性能怎样优化

组件主动扫描带来的问题默认状况下,咱们会应用 @SpringBootApplication 注解来主动获取利用的配置信息,但这样也会给利用带来一些副作用。应用这个注解后,会触发主动配置( auto-configuration )和 组件扫描 ( component scanning ),这跟应用 @Configuration、@EnableAutoConfiguration 和 @ComponentScan 三个注解的作用是一样的。这样做给开发带来不便的同时,也会有三方面的影响: 1、会导致我的项目启动工夫变长。当启动一个大的应用程序,或将做大量的集成测试启动应用程序时,影响会特地显著。 2、会加载一些不须要的多余的实例(beans)。 3、会减少 CPU 耗费。 针对以上三个状况,咱们能够移除 @SpringBootApplication 和 @ComponentScan 两个注解来禁用组件主动扫描,而后在咱们须要的 bean 上进行显式配置: //// 移除 @SpringBootApplication and @ComponentScan, 用 @EnableAutoConfiguration 来代替//@SpringBootApplication@Configuration@EnableAutoConfigurationpublic class App01 {public static void main(String[] args) {SpringApplication.run(App01.class, args);}}以@SpringBootApplication 启动工夫8.56秒 将Servlet容器变成Undertow默认状况下,Spring Boot 应用 Tomcat 来作为内嵌的 Servlet 容器 能够将 Web 服务器切换到 Undertow 来进步利用性能。Undertow 是一个采纳 Java 开发的灵便的高性能 Web 服务器,提供包含阻塞和基于 NIO 的非梗塞机制。Undertow 是红帽公司的开源产品,是 Wildfly 默认的 Web 服务器。首先,从依赖信息里移除 Tomcat 配置: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency>而后增加 Undertow: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-undertow</artifactId></dependency>SpringBoot JVM参数调优这个依据服务器的内存大小,来设置堆参数。 -Xms :设置Java堆栈的初始化大小 ...

March 25, 2022 · 1 min · jiezi

关于springboot:在-Sonic-云真机使用-Scrcpy-是一种什么样的体验

v1.3.2-release正式公布啦~该版本上新了Scrcpy投屏,然而安卓投屏曾经有MiniCap了。到底Scrcpy能带来怎么的体验呢? 以往Sonic应用的Minicap投屏如果咱们把Minicap画质压缩到80,咱们能够看到投屏成果清晰度还是算高的: 而后咱们看一下带宽: 很显著,清晰度达到了咱们的要求,然而带宽切实是太高了,这还是我略微压缩过的,如果是一些分辨率稍大一点的手机,可能每帧达到1M左右,会造成FPS降落,而且局域网带宽重大负荷。 于是Sonic之前应用的是Minicap官网说的形式: Usable to very smooth FPS depending on device. Older, weaker devices running an old version of Android can reach 10-20 FPS. Newer devices running recent versions of Android can usually reach 30-40 FPS fairly easily, but there are some exceptions. For maximum FPS we recommend running minicap at half the real vertical and horizontal resolution.压缩投屏的分辨率来取得更高的FPS,踩过不少坑之后,拿到的清晰度就是咱们看到的 能够看到图片的文字都曾经比拟含糊,然而带宽的确升高了不少,FPS 也达到了顺畅的水准: 除此之外,我还做了丢帧,雷同图片的间接不发送,其余的抛弃三分之一的帧,然而带宽还是比拟高。当然,Minicap还有一个很致命的毛病,兼容性太差了,不仅小米、vivo、LGE有兼容性问题,最新的华为P50都曾经无奈兼容了。 Scrcpy的晋升Scrcpy咱们将socket桥接过来解决,间接发送h264裸流给前端渲染,清晰度是怎么样的呢? 能够看进去,投屏清晰度曾经和Minicap最清晰的时候有得一拼了(实践上比Minicap要略微清晰),那么他的带宽是多少呢? 对你没有看错,一帧根本不超10KB!那么Scrcpy带来的投屏体验天然是很不错的,那为什么Sonic不间接舍弃Minicap呢?Scrcpy也有一个毛病,就是会造成CPU功耗减少、设施发热会更重大一些,我认为这种危险应该让用户去衡量,于是将两种投屏形式都做进去,让用户能够切换着应用。 Scrcpy提供不少好的思路,iOS目前始终用wda的mjpegserver,带宽耗费和FPS都没能达到称心的水平,接下来,须要对iOS的投屏也要做一番优化了!

March 25, 2022 · 1 min · jiezi

关于springboot:微服务下一键启动多个server

微服务下一键启动多个server在.idea/workspace.xml中设置如下: <component name="RunDashboard"> <option name="configurationTypes"> <set> <option value="SpringBootApplicationConfigurationType" /> </set> </option> </component>

March 22, 2022 · 1 min · jiezi

关于springboot:spring-boot-22-加载配置文件流程梳理

废话不多说,间接上图!再次感叹,不得不说DEBUG是梳理源码的神不二法器,哈哈~

March 18, 2022 · 1 min · jiezi

关于springboot:springcloud子模块项目启动无法配置数据源Failed-to-configure-a-DataSource

谬误详情:07:31:04.082 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - [report,40] - ***************************APPLICATION FAILED TO START***************************Description:Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.Reason: Failed to determine a suitable driver classAction:Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).07:31:04.083 [Thread-1] WARN c.a.n.c.h.HttpClientBeanHolder - [shutdown,108] - [HttpClientBeanHolder] Start destroying common HttpClient07:31:04.083 [Thread-1] WARN c.a.n.c.h.HttpClientBeanHolder - [shutdown,114] - [HttpClientBeanHolder] Destruction of the endDisconnected from the target VM, address: '127.0.0.1:63119', transport: 'socket'Process finished with exit code 1我的项目环境:springcloud+Nacos+mybatisPlus ...

March 16, 2022 · 1 min · jiezi

关于springboot:SpringBoot-2x-实战仿B站高性能后端项目

download:SpringBoot 2.x 实战仿B站高性能后端我的项目2021 年 Node.js 的发展趋势世界各地的开发者对 2021 年 Node.js 的发展趋势做了很多预测。在下文中,咱们将解说往年预期的 Node.js 趋势。Node.js 为什么如此有名呢?近些年来,Node.js 凭借其高度灵活和极其轻量的个性,变得非常流行。Node.js 具备大量的 JavaScript 库用于简化开发流程。Node.js 的开源属性也使得它在 web 和移动利用开发方面变得非常出名。根据最近的统计,可能看出: 目前有超过 50% 的开发者在自己的我的项目中使用 Node.js。在美国,基于 Node.js 创建的网站超过 28000 个 。AliExpress、eBay 等出名公司很大程度上依赖于 Node.js。包含 PayPal、Netflix 和 Groupon 在内的大流量的网站都在使用 Node.js。 Node.js 自 2009 年在市场上推出就变得非常受欢迎。Node.js 在 Github 中具备 75.9k stars、3k watchers,还有 19k forks,在 Stack share 中具备 71.8k 的关注者以及 8.3k 的同意。这些数字足以描述 Node.js 流行程度。出名的科技巨头,比如 Netflix 和 Microsoft 都在使用 Node.js。Node.js 胜利在 StackOverflow 2021 年开发者考察中位居榜首,其中超过 50% 的考察参与者声称正在我的项目中使用 Node.js。 ...

March 16, 2022 · 1 min · jiezi

关于springboot:spring-boot-保存到mysql时间不对的问题

明天遇到了一个很无语的的问题:spring boot 保留到mysql工夫不对的问题 在办法里打了n遍的断点,确定我save的数据没问题,设置的day就是3.16日 后果每次到数据库一看: 保留的却是3.15日。 在打了n编断点确定我保留的day没错后,在网上查找材料。 发现能够是后盾与数据库连贯,没有设置时区。 在与后盾连接处加上即可:url: ....&serverTimezone=Asia/Shanghai 最初就能保留出失常的3.16日 这揭示咱们,与数据库连贯记得加上时区。还有指定utf8编码等

March 16, 2022 · 1 min · jiezi

关于springboot:聊聊如何让springboot拦截器的执行顺序按我们想要的顺序执行

前言最近敌人和我提了一个挺乏味的问题:他们有个我的项目用了他们框架部提供的jwt token校验填充组件,实现原理大略是,通过springboot拦截器来校验token,如果token非法,就解析token,将token携带的业务信息map填充到threadlocal外面,不便后续业务应用。 敌人的问题就是他想往这个threalocal外面的业务map再扩大一些业务字段,但因为这个组件不是敌人的部门开发的,他就不能改源码,只能通过扩大的形式。 他的思路就是他也写一个拦截器,在这个拦截器外面做业务填充。这边有个前提就是框架部的执行机会得在敌人写的拦截器之前,敌人的做法是在他写的拦截器下面加@Order注解,不过发现不论用。于是就找我讨论一下这个问题。 形象进去的问题就是题目说的如何让springboot拦截器的执行程序按咱们想要的程序执行 思路办法一:本人的业务我的项目写一个和框架组截然不同的类即这个类和框架组提供的包名和类名一样,而后改这个类,这个实现原理是利用了类的加载程序 办法二:利用org.springframework.web.servlet.config.annotation.InterceptorRegistration#order()不过这个order办法是spring 4.3+版本后才提供。 具体应用形如下 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(helloHandlerInterceptor).addPathPatterns("/**").order(100); registry.addInterceptor(otherHelloHandlerInterceptor).addPathPatterns("/**").order(-1); }通过配置order()的值,值越小,优先级越高。不配默认是0 那为啥要配置这个呢,如果对springmvc有略微深刻一下的话,拦截器链最终是会用到 protected List<Object> getInterceptors() { return this.registrations.stream() .sorted(INTERCEPTOR_ORDER_COMPARATOR) .map(InterceptorRegistration::getInterceptor) .collect(Collectors.toList()); }排序就是依据这个order来的 总结本文提供的计划二实用于spring 4.3+版本,低于该版本,请谨慎。 demo链接https://github.com/lyb-geek/springboot-learning/tree/master/springboot-interceptor-order

March 15, 2022 · 1 min · jiezi

关于springboot:spring-boot-实现锁的几种方式

因为以后的我的项目中因为多线程操作同一个实体,会呈现数据笼罩的问题,后保留的实体把先保留的实体的数据给笼罩了。 于是查找了锁的实现的几种形式。 但写到最初发现,其实本人能够写sql 更新须要更新的字段即可,这个操作放在文章尾部。 先来说一下实现锁的几种形式。 对办法加锁不同于对数据库数据加锁,这种形式是对类中的某个办法加锁。 synchronizedjava中曾经有了内置锁:synchronized, 它的特点是应用简略,所有交给JVM去解决,不须要显示开释 示例: public class SynchronizedMethod { public synchronized void method() { System.out.println("Hello World!"); }}如代码可见,只有办法上加上synchronized关键字就能够了。 当初来测试一下 不应用synchronized时测试: test字段初始化为0,通过new Thread测试100个线程高并发量下test每次 + 1。 controller: public void batchSave() { for (int i = 0; i < 100; i++) { int finalI = i; new Thread(() -> { logService.test(); }).start(); }service: @Override public void test() { Client client = clientRepository.findById(9L).get(); client.setTest(client.getTest() + 1); clientRepository.save(client); }测试后果:为15 阐明在高并发量的状况下,呈现了数据笼罩的状况,线程并没有期待上一个线程实现再进行操作,100个线程进行+1操作,最终只加了15. ...

March 14, 2022 · 2 min · jiezi

关于springboot:事务注解失效的问题

最近我的项目中遇到并发的问题,所以须要设置锁。因为并发量并不大,所以采纳了乐观锁来锁住数据。然而依照网上设置好了乐观锁之后,运行时却报 no transaction is in progress,于是查找事务注解生效的起因,并总结几个事务注解会生效的状况。 背景测试逻辑:实体新增test字段,初始化为0,调用save函数时开始测试,接着调用filter函数。 filter函数用了事务注解,模仿100个线程高并发状况下,每个线程都用乐观锁获取同一个id的实体,让test字段+1。 dao层的findClientById用了乐观锁,在咱们没有将其提交事务之前,其余线程是不能获取批改的,须要期待。 期待后果:test字段为100。 client实体: @JsonView(base.class) private int test = 0;service层: public void save(List<Log> logs) throws ParseException { this.filter(logs); } @Transactional(rollbackFor = Exception.class) void filter(List<Log> logs) throws ParseException { for (int i = 0; i < 100 ; i++) { new Thread(() -> { Client client = clientRepository.findClientByIdWithPessimisticLock(9L).get(); client.setTest(client.getTest() + 1); clientRepository.save(client); }).start();dao层: /** * 查问时加上乐观锁 * 在咱们没有将其提交事务之前,其余线程是不能获取批改的,须要期待 * @param id clientId * @return */ @Lock(value = LockModeType.PESSIMISTIC_WRITE) @Query("select a from Client a where a.id = :id") Optional<Client> findClientByIdWithPessimisticLock(Long id);测试后果: no transaction is in progress ...

March 13, 2022 · 2 min · jiezi

关于springboot:Java开发热门框架SpringBoot初学入门教程

SpringBoot作为当下Java开发最罕用的技术框架,置信你也肯定听过很屡次了。 那么到底什么是SpringBoot?SpringBoot又有什么用呢?跟着能源节点的视频带你疾速入们springboot 视频资源: https://www.bilibili.com/vide... SpringBoot简介1、原有Spring框架优缺点剖析1.1 长处Spring是Java企业版(Java Enterprise Edition,JEE,也称J2EE)的轻量级代替品。无需开发重量级的Enterprise JavaBean(EJB),Spring为企业级Java开发提供了一种绝对简略的办法,通过依赖注入和面向切面编程,用简略 的Java对象(Plain Old Java Object,POJO)实现了EJB的性能。 1.2 毛病尽管Spring的组件代码是轻量级的,但它的配置却是重量级的。 一开始,Spring用XML配置,而且是很多XML配置。 Spring 2.5引入了基于注解的组件扫描,这打消了大量针对应用程序本身组件的显式XML配置。 Spring 3.0引入 了基于Java的配置,这是一种类型平安的可重构配置形式,能够代替XML。 所有这些配置都代表了开发时的损耗。因为在思考Spring个性配置和解决业务问题之间须要进行思维切换,所以编 写配置挤占了编写利用程序逻辑的工夫。和所有框架一样,Spring实用,但与此同时它要求的回报也不少。  除此之外,我的项目的依赖治理也是一件耗时耗力的事件。在环境搭建时,须要剖析要导入哪些库的坐标,而且还须要剖析导入与之有依赖关系的其余库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会重大妨碍我的项目的开发进度。 2、SpringBoot概念简介Spring Boot是Spring公司的一个顶级我的项目,和Spring Framework是一个级别的。 Spring Boot实际上是利用Spring Framework 4 主动配置个性实现。编写我的项目时不须要编写xml文件。倒退到当初,Spring Boot曾经具备很大的生态圈,各种支流技术曾经都提供了Spring Boot的启动器。 启动器?Spring框架在我的项目中作用是Spring整合各种其余技术,让其余技术应用更加不便。Spring Boot的启动器实际上就是一个依赖。这个依赖中蕴含了整个这个技术的相干jar包,还蕴含了这个技术的主动配置,以前绝大多数XML配置都不须要配置了。当然了,启动器中主动配置无奈实现所有内容的主动配置,在应用Spring Boot时还须要进行大量的配置(这个配置不是在xml中了,而是在properties或yml中即可)。如果是Spring本人封装的启动器的artifact id名字满足:spring-boot-starter-xxxx,如果是第三方公司提供的启动满足:xxxx-spring-boot-starter。当前每次应用Spring Boot整合其余技术时首先须要思考导入启动器。 3、SpringBoot特色应用Spring Boot能够创立独立的Spring应用程序; 在Spring Boot中间接嵌入了Tomcat、Jetty、Undertow等Web容器,所以在应用SpringBoot做Web开发时不须要部署WAR文件; 通过提供本人的启动器(Starter)依赖,简化我的项目构建配置; 尽量的主动配置Spring和第三方库; 相对没有代码生成,也不须要XML配置文件。 4、Spring Boot版本介绍SNAPSHOT:快照版,即开发版。 CURRENT:最新版,然而不肯定是稳定版。 GA:General Availability,正式公布的版本。 5、Spring Boot的外围起步依赖:起步依赖实质上是一个Maven我的项目对象模型(Project Object Model,POM),定义了对其余库的传递依赖,这些货色加在一起即反对某项性能。 简略的说,起步依赖就是将具备某种性能的坐标打包到一起,并提供一些默认的性能。 主动配置:Spring Boot的主动配置是一个运行时(更精确地说,是应用程序启动时)的过程,思考了泛滥因素,才决定Spring配置应该用哪个,不该用哪个。该过程是Spring主动实现的。 当初你晓得什么是SpringBoot了吗?赶快把握吧!能源节点的springboot视频中还有更多内容~ https://www.bilibili.com/vide...

March 9, 2022 · 1 min · jiezi

关于springboot:浅谈Transactional与AOP

之前就在后盾的dao层留神到,根本对数据库进行删除和编辑的操作都会加上@Transactional注解(如下),过后只是大略明确是进行事务回滚的。然而也不太分明具体的执行过程,以前具体应用场景。于是搜寻了相干材料来了解并记录一下。 @Modifying @Transactional void deleteAllByDistrictId(Long districtId);@Transactional简略概括应用这个注解的类或者办法的事务由spring解决,即是办法外面对数据库操作,如果失败则spring负责回滚操作,胜利则提交操作。也就是上周学长提到的保障事务的原子性:对数据进行操作的时候,要么全都执行,要么全都不执行。 举个例子: 以后办法须要将数据插入两个数据表:如果第一张表插入胜利了,然而插入第二张的时候失败了,怎么解决? 1.要么就保障两张表都插入胜利2.要么就进行回滚,勾销对第一张表的操作。 @Transactional注解就是为了帮忙咱们治理这些事务。 AOP查找材料的时候我发现这么一句话:@Transactional原理是基于spring aop实现的。那么Aop又是什么呢? AOP(Aspect-oriented programming):面向切面編程。这种在运行时,动静地将代码切入到类的指定办法、指定地位上的编程思维就是面向切面的编程。 与之绝对是的以前常应用的OOP (Object-oriented programming)面向对象 上面用一个场景来阐明一下应用Aop带给咱们的益处: 场景:如果说咱们曾经实现了一个我的项目,当初想退出日志性能,在save办法中打印日志。 如果咱们仍然应用OOP面向对象,那么咱们会这么做: 在save办法代码里,写上打印日志的的代码。有时候写错时甚至会导致原来执行失常的办法执行失败。如果咱们应用了AOP呢? @Around("execution(* Controller.save(..))")public void print() throws Throwable {咱们就能够应用切面,当Controller.save执行的时候,执行该打印日志的函数。这样的做法,对原有代码毫无入侵性,这就是AOP的益处了,把和主业务无关的事件,放到代码里面去做。 切面执行机会有五种:「@Before」 :在指标办法调用前去告诉「@AfterReturning」 :在指标办法返回或异样后调用「@After」 :在指标办法返回后调用「@AfterThrowing」 :在指标办法异样后调用「@Around」 :将指标办法封装起来,本人确定调用机会 在理解AOP是啥之后,咱们再来看看实现原理: AOP 实现次要分为两类:1.动态 AOP2.动静 AOP 这里咱们次要讲动静 AOP ,因为spring 中 AOP 的实现是就说通过动静代理实现的。 什么是代理呢,就是我再生成一个代理类,去代理Controller的save()办法,代码大略就长这样: class ControllerProxy { private Controller controller; public void save() { controller.save(); print() // 打印日志 }}所以在方才那张图中,spring实现AOP过程大略是这样的:(这里依据不同的切面机会过程略有不同,这里是After切面) Spring AOP就是基于动静代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会应用JDK Proxy,去创立代理对象。 @Transactional@Transactional原理就是基于spring aop实现的。 ...

March 7, 2022 · 1 min · jiezi

关于springboot:如何在-Spring-Boot-优雅关闭加入一些自定义机制

集体创作公约:自己申明创作的所有文章皆为本人原创,如果有参考任何文章的中央,会标注进去,如果有疏漏,欢送大家批评。如果大家发现网上有剽窃本文章的,欢送举报,并且踊跃向这个 github 仓库 提交 issue,谢谢反对~咱们晓得从 Spring Boot 2.3.x 这个版本开始,引入了优雅敞开的机制。咱们也在线上部署了这个机制,来减少用户体验。尽管当初大家基本上都通过最终一致性,以及事务等机制,来保障了就算非优雅敞开,也能够放弃业务正确。然而,这样总会带来短时间的数据不统一,影响用户体验。所以,引入优雅敞开,保障以后申请解决完,再开始 Destroy 所有 ApplicationContext 中的 Bean。 优雅敞开存在的问题ApplicationContext 的敞开过程简略来说分为以下几个步骤(对应源码 AbstractApplicationContext 的 doClose 办法): 勾销以后 ApplicationContext 在 LivBeanView 的注册(目前其实只蕴含从 JMX 上勾销注册)公布 ContextClosedEvent 事件,同步解决所有这个事件的 Listener解决所有实现 Lifecycle 接口的 Bean,解析他们的敞开程序,并调用他们的 stop 办法Destroy 所有 ApplicationContext 中的 Bean敞开 BeanFactory简略了解优雅敞开,其实就是在下面的第三步中退出优雅敞开的逻辑实现的 Lifecycle,包含如下两步: 切断内部流量入口:具体点说就是让 Spring Boot 的 Web 容器间接回绝所有新收到的申请,不再解决新申请,例如间接返回 503.期待承载的 Dispatcher 的线程池解决完所有申请:对于同步的 Servlet 过程其实就是解决 Servlet 申请的线程池,对于异步响应式的 WebFlux 过程其实就是所有 Web 申请的 Reactor 线程池解决完以后所有 Publisher 公布的事件。首先,切断内部流量入口保障不再有新的申请到来,线程池解决完所有申请之后,失常的业务逻辑也是失常走完的,在这之后就能够开始敞开其余各种元素了。 然而,咱们首先要保障,优雅敞开的逻辑,须要在所有的 Lifecycle 的第一个最保险。这样保障肯定所有申请解决完,才会开始 stop 其余的 Lifecycle。如果不这样会有啥问题呢?举个例子,例如某个 Lifecycle 是负载均衡器的,stop 办法会敞开负载均衡器,如果这个 Lifecycle 在优雅敞开的 Lifecycle 的 stop 之前进行 stop,那么可能会造成某些在 负载均衡器 stop 后还没解决完的申请,并且这些申请须要应用负载均衡器调用其余微服务,执行失败。 ...

March 5, 2022 · 7 min · jiezi

关于springboot:SpringBoot整合缓存支持

注解配置与EhCache应用1.1pom文件引入 1.2新建ehcache.xml 文件 配置信息介绍 <!--name:缓存名称。maxElementsInMemory:缓存最大个数。eternal:对象是否永恒无效,一但设置了,timeout将不起作用。timeToIdleSeconds:设置对象在生效前的容许闲置工夫(单位:秒)。仅当eternal=false对象不是永恒无效时应用,可选属性,默认值是0,也就是可闲置工夫无穷大。timeToLiveSeconds:设置对象在生效前容许存活工夫(单位:秒)。最大工夫介于创立工夫和生效工夫之间。仅当eternal=false对象不是永恒无效时应用,默认是0.,也就是对象存活工夫无穷大。overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有本人的一个缓冲区。maxElementsOnDisk:硬盘最大缓存个数。diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.diskExpiryThreadIntervalSeconds:磁盘生效线程运行工夫距离,默认是120秒。memoryStoreEvictionPolicy:当达到maxElementsInMemory限度时,Ehcache将会依据指定的策略去清理内存。默认策略是LRU(最近起码应用)。你能够设置为FIFO(先进先出)或是LFU(较少应用)。clearOnFlush:内存数量最大时是否革除。-->1.3代码应用Cacheable 1.4革除缓存 1.5 启动退出缓存@EnableCaching // 开启缓存注解 关键词:java培训

March 4, 2022 · 1 min · jiezi

关于springboot:WGCLOUD主机列表中的主机连接数量是什么

主机连贯数量包含:tcp、udp、inet等所有协定的连贯数量

March 4, 2022 · 1 min · jiezi

关于springboot:Spring-Cloud-Sleuth-和-Zipkin-进行分布式跟踪使用指南

分布式跟踪容许您跟踪分布式系统中的申请。本文通过理解如何应用 Spring Cloud Sleuth 和 Zipkin 来做到这一点。 对于一个做所有事件的大型应用程序(咱们通常将其称为单体应用程序),跟踪应用程序内的传入申请很容易。咱们能够跟踪日志,而后弄清楚申请是如何解决的。除了应用程序日志自身之外,咱们无需查看其余任何内容。 随着工夫的推移,单体应用程序变得难以扩大,难以解决大量申请以及随着代码库规模的不断扩大向客户提供新性能。这导致将单体架构合成为微服务,这有助于扩大单个组件并有助于更快地交付。 但并非所有闪耀的都是黄金,对吧?微服务也是如此。咱们将整个单体零碎拆分为微服务,由一组本地函数调用解决的每个申请当初都被调用一组分布式服务所取代。这样一来,咱们就失去了追踪在单体利用中很容易实现的申请之类的事件。当初,要跟踪每个申请,咱们必须查看每个服务的日志,并且很难关联。 因而,在分布式系统的状况下,分布式跟踪的概念有助于跟踪申请。 什么是分布式跟踪?分布式跟踪是一种机制,咱们能够应用它跟踪整个分布式系统中的特定申请。它容许咱们跟踪申请如何从一个零碎停顿到另一个零碎,从而实现用户的申请。 分布式跟踪的要害概念分布式跟踪蕴含两个次要概念: 跟踪 ID跨度编号跟踪 id 用于跟踪传入申请并在所有组合服务中跟踪它以满足申请。Span id 逾越服务调用以跟踪接管到的每个申请和收回的响应。 让咱们看一下图表。 传入的申请没有任何跟踪 ID。拦挡调用的第一个服务会生成跟踪 ID“ID1”及其跨度 ID“A”。span id“B”涵盖了从服务器一的客户端发出请求到服务器二接管、解决并收回响应的工夫。 带有 Spring Cloud Sleuth 的 Spring Boot 示例让咱们创立一个集成了 Spring Cloud Sleuth 的应用程序。首先,让咱们拜访https://start.spring.io/并应用依赖项“Spring Web”和“Spring Cloud Sleuth”创立一个应用程序。 当初让咱们创立一个带有两个申请映射的简略控制器。 public class Controller { private static final Logger logger = LoggerFactory.getLogger(Controller.class); private RestTemplate restTemplate; @Value("${spring.application.name}") private String applicationName; public Controller(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @GetMapping("/path1") public ResponseEntity path1() { logger.info("Request at {} for request /path1 ", applicationName); String response = restTemplate.getForObject("http://localhost:8090/service/path2", String.class); return ResponseEntity.ok("response from /path1 + "+ response); }@GetMapping("/path2")public ResponseEntity path2(){ logger.info("Request at {} at /path2", applicationName); return ResponseEntity.ok("response from /path2 ");}在这里,我创立了两条门路,Path1调用Path2固定端口 8090。这里的想法是运行同一应用程序的两个独自实例。 ...

March 3, 2022 · 2 min · jiezi

关于springboot:SpringBootMybatisPlusMysqlShardingJDBC分库分表实践

一、序言在理论业务中,单表数据增长较快,很容易达到数据瓶颈,比方单表百万级别数据量。当数据量持续增长时,数据的查问性能即便有索引的帮忙下也不尽如意,这时能够引入数据分库分表技术。 本文将基于SpringBoot+MybatisPlus+Sharding-JDBC+Mysql实现企业级分库分表。 1、组件及版本抉择SpringBoot 2.6.xMybatisPlus 3.5.0Sharding-JDBC 4.1.1Mysql 5.7.352、预期指标应用上述组件实现分库分表,简化起见只探讨分表技术实现分表后的逻辑表与物理表间的增删查改引入逻辑删除和应用MybatisPlus内置分页技术残缺我的项目源码拜访地址。 二、代码实现为了简化分表复杂性,专一于分表整体实现,简化分表逻辑:依照UserId的奇偶属性别离进行分表。以订单表这一典型场景为例,一般来说无关订单表,通常具备如下共性行为: 创立订单记录查问XX用户的订单列表查问XX用户的订单列表(分页)查问XX订单详情批改订单状态删除订单(逻辑删除)接下来通过代码实现上述指标。 (一)素材筹备1、实体类@Data@TableName("bu_order")public class Order { @TableId private Long orderId; private Integer orderType; private Long userId; private Double amount; private Integer orderStatus; @TableLogic @JsonIgnore private Boolean deleted;}2、Mapper类@Mapperpublic interface OrderMapper extends BaseMapper<Order> {}3、全局配置文件spring: config: use-legacy-processing: true shardingsphere: datasource: ds1: driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://127.0.0.1:3306/sharding-jdbc2?serverTimezone=UTC username: root password: 123456 names: ds1 props: sql: show: true sharding: tables: bu_order: actual-data-nodes: ds1.bu_order_$->{0..1} key-generator: column: order_id type: SNOWFLAKE table-strategy: inline: algorithm-expression: bu_order_${user_id%2} sharding-column: user_id(二)增删查改1、保留数据因为根据主键的奇偶属性对原表分表,分表后每张表的数据量是分表前的二分之一。依据须要也能够自定义分表数量(比方10张),新分表后的数据量是不分表前的十分之一。 ...

March 1, 2022 · 1 min · jiezi

关于springboot:本周解决的一些问题

问题1 @Autowired 注入失败 @Autowired private DingService dingService;在我的项目中service是用 @Autowired依赖注入,用debug测试的时候看到service的确为null。 一开始想法:想用new的模式手动生成一个service,然而在查找材料之后发现这种形式是有弊病的,于是不采纳。 DingServiceImpl dingService1 = new DingServiceImpl();弊病:在spring中如果应用new创立一个对象时,这个对象将不在受spring管理器治理,这样的话就绕过了容器的依赖注入过程,也可能呈现获取不到应有的属性这种状况。阐明:Spring是一个bean的容器,由容器负责对象的初始化和依赖注入。当咱们想要从中获取一个Bean的实例时,就从Spring容器中获取。 最初查找材料之后发现起因:@EntityListeners(LogListener.class)这里是在Listener中应用了@Autowired,导致的注入失败。 在利用的Filter或Listener中应用了@Autowired ,注入为空web容器启动是依照肯定程序的,即:Listener --> Filter -->Servlet。因为Filter和Listener加载程序优先于spring容器初始化实例,所以会呈现null。Spring的入口就在Servlet里。能够用ApplicationContext依据bean名称(留神名称为实现类而不是接口)去获取bean。 之前学长就采纳的这种办法:ApplicationContext去获取bean。传送门:https://segmentfault.com/a/11... 这种办法须要新建文件,自定义实现ApplicationContextAware。 对于Listener来说,我找到了一种更不便一点的办法,不须要新建文件来实现类。 @Componentpublic class LogListener implements ServletContextListener { @Autowired private DingService dingService; @Override public void contextInitialized(ServletContextEvent sce) { WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext()) .getAutowireCapableBeanFactory().autowireBean(this); }只有继承ServletContextListener,并在在监听类的contextInitialized的办法中加上如上代码即可。原理是一样的,都是从ApplicationContext中获取bean. 总结一下@Autowired为null的几种状况:1.在利用的Filter或Listener中应用了@Autowired2.组件下面没有退出了适合的注解。例如:@Service, @Component等,Bean没有交付给Spring容器。3.把@Autowired注解加在了一个动态属性上,注入为空。4.查看@Autowired注入类应用的办法是否为private,如果为private的话在生成动静代理的话@Autowired注入的依赖将为空。5.查看是不是new了一个对象,这样的话就绕过了容器的依赖注入过程,也可能呈现获取不到应有的属性这种状况。 目前对于ApplicationContext和Servlet这些还不太熟悉,待有理解之后再来补充。长路漫漫。 2.定时器误差目前我的项目是2分钟发送一次定时工作,并且会判断以后发送工作是否与上次距离2分钟,如果是则发送。通过老师的阐明和谷歌的搜寻,才理解这种误差。个别会有1到2毫秒的提早,写代码的时候须要思考进去这种误差。 3.双线程导致的问题 解决:在保留前对数据库从新获取最初交互工夫字段

February 28, 2022 · 1 min · jiezi

关于springboot:若依系统Vue版笔记一

若依管理系统是一个齐全开源的后端管理系统,前后端拆散版本地址:RuoYi-Vue一、启动1、下载zip文件,解压,doc文件夹中为开发环境搭建手册 后端启动我的项目是ruoyi-admin,启动类是com.ruoyi.RuoYiApplication;前端我的项目是ruoyi-ui后端我的项目应用maven构建,应用前需确保maven环境;前端是vue我的项目,应用前需确保node环境后端我的项目依赖mysql和redis,启动前须要批改application.yml配置文件和application-druid.yml配置文件批改对应的配置例如端口等。*2、创立数据库,并且执行sql文件夹下的ry_20210108.sql、quartz.sql,批改application.yml配置文件和application-druid.yml配置文件中的redis和mysql的连贯配置3、在我的项目根目录下执行mvn clean package -DskipTests命令下载后端我的项目依赖;在ruoyi-ui模块下执行npm install --registry=https://registry.npm.taobao.org命令装置前端我的项目依赖4、关上ruoyi-admin我的项目的启动类com.ruoyi.RuoYiApplication,并执行main办法,运行后端代码;关上ruoyi-ui模块,执行命令npm run dev运行前端代码5、浏览器输出网址http://127.0.0.1

February 28, 2022 · 1 min · jiezi

关于springboot:WGCLOUD监控系统的服务端和代理端用什么协议通信的

是http啦,简略牢靠平安,如下图所示

February 26, 2022 · 1 min · jiezi

关于springboot:Spring-Boot如何自定义Spring-Boot-Starter

本文介绍咱们都晓得Spring Boot我的项目由一个个的starter形成,比方web的starter,redis的starter等等。咱们通过maven引入对应的starter,简直毋庸配置就能够完满应用集成的spring mvc或redis. 那么咱们如何自定义一个starter呢? 本文用将示如何应用SpringBoot的Auto-Configuration个性创立本人的Spring Boot Starter。 假如Toy为咱们须要集成为starter框架或者类,并且心愿在利用启动的时候就加载到Spring上下文中供咱们调用。 有的小伙伴可能会问为什么要这样做?间接将Toy申明为Spring的bean不就好了。 答案必定是能够这样做,不过秉承Spring Boot疾速上手的准则,通过引入starter的形式能够更加疾速应用集成的咱们想要的性能或者个性,就好比下面的Toy。 又比方mybatis,因为咱们无奈批改mybatis源码,路径之一是通过@Bean的形式在办法上创立SqlSessionFactory bean,并在Spring Boot利用中应用。 路径二则是通过创立starter,须要用到mybatis的中央引入mybatis的starter就可实现mybatis的集成。 在很多我的项目须要集成mybatis的状况下,starter的形式会更为疾速高效。 我的项目构造本我的项目分为两个模块: toy-sample-app 和toy-spring-boot-starter toy-sample-app: 演示如何引入本人创立的startertoy-spring-boot-starter: starter模块,用于构建Toy Spring Bean 供演示我的项目应用代码介绍toy-spring-boot-starterMETA-INF/spring.factories文件该文件指明了主动注入的的类名,Spring Boot利用启动的时候会将该类初始化并加载到上下文中。 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ cn.bugkit.toy.autoconfigure.ToyAutoConfigurationToyAutoConfiguration文件@Configuration注解阐明是Spring的配置类 @EnableConfigurationProperties(ToyProperties.class)注解指定了须要应用的属性配置类 package cn.bugkit.toy.autoconfigure;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * @author bugkit * @since 2022.2.24 */@Configuration@EnableConfigurationProperties(ToyProperties.class)public class ToyAutoConfiguration { @Autowired private ToyProperties toyProperties; @Bean public Toy toy(){ return new Toy(toyProperties.getName(),toyProperties.getPassword(), toyProperties.getWeight()); }}ToyProperties文件该类申明了须要从application.properties文件读取的属性,供上述文件的toy()办法构建所须要的Toy对象。 /** * @author bugkit * @since 2022.2.24 */@Configuration@ConfigurationProperties(prefix = "toy")public class ToyProperties { private String name; private String password; private int weight; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; }}Toy文件提供了咱们须要的showInfo()办法,具体在toy-sample-app我的项目中用到 ...

February 24, 2022 · 2 min · jiezi

关于springboot:MybatisPlus多表连接查询-一对一一对多多对多查询

一、序言(一)背景内容软件应用技术架构中DAO层最常见的选型组件为MyBatis,相熟MyBatis的敌人都分明,曾几何时MyBatis是如许的景色,应用XML文件解决了简单的数据库拜访的难题。时至今日,已经的屠龙者终成恶龙,以XML文件为根底的数据库拜访技术变得臃肿、简单,保护难度直线回升。 MybatisPlus对常见的数据库拜访进行了封装,拜访数据库大大减少了XML文件的依赖,开发者从臃肿的XML文件中取得了较大限度的解脱。 MybatisPlus官网并没有提供多表连贯查问的通用解决方案,然而连贯查问是相当广泛的需要。解决连贯查问有两种需要,一种是持续应用MyBatis提供XML文件解决形式;另一种本文提供的解决方案。 事实上笔者强烈推荐彻底辞别通过XML拜访数据库,并一直摸索旧式更加敌对、更加天然的解决形式,现分享最新的MybatisPlus技术的研究成果。 <img src="https://www.altitude.xin/typora/image-20211021114957682.png" alt="image-20211021114957682" style="zoom:50%;" /> (二)场景阐明为了阐明连贯查问的关系,这里以学生、课程及其关系为示例。 <img src="https://www.altitude.xin/typora/image-20211020194255298.png" alt="image-20211020194255298" style="zoom:50%;" /> (三)后期筹备此局部须要读者把握以下内容:Lambda 表达式、特地是办法援用;函数式接口;流式运算等等,否则了解起来会有些吃力。 <img src="https://www.altitude.xin/typora/image-20211021135113431.png" alt="image-20211021135113431" style="zoom:50%;" /> 实体类与 Vo 的映射关系,作者创造性的引入特地结构器,正当利用继承关系,极大的不便了开发者实现实体类向 Vo 的转换。 空指针异样疏忽不解决,借助Optional类实现,详情移步Java8 新个性查看。 二、一对一查问一对一查问最典型的利用场景是将id替换成name,比方将userId替换成userName。 (一)查问单条记录查问单条记录是指返回值仅有一条记录,通常是以惟一索引作为条件的返回查问后果。 1、示例代码/** * 查问单个学生信息(一个学生对应一个部门) */public UserVo getOneUser(Integer userId) { LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class) .eq(User::getUserId, userId); // 先查问用户信息 User user = userMapper.selectOne(wrapper); // 转化为Vo UserVo userVo = Optional.ofNullable(user).map(UserVo::new).orElse(null); // 从其它表查问信息再封装到Vo Optional.ofNullable(userVo).ifPresent(this::addDetpNameInfo); return userVo;}从属表信息补充 /** * 补充部门名称信息 */private void addDetpNameInfo(UserVo userVo) { LambdaQueryWrapper<Dept> wrapper = Wrappers.lambdaQuery(Dept.class) .eq(Dept::getDeptId, userVo.getDeptId()); Dept dept = deptMapper.selectOne(wrapper); Optional.ofNullable(dept).ifPresent(e -> userVo.setDeptName(e.getDeptName()));}2、实践剖析查问单个实体共分为两个步骤:依据条件查问主表数据(需解决空指针异样);封装 Vo 并查问从属表数据。 ...

February 24, 2022 · 3 min · jiezi

关于springboot:第十五节SpringBoot使用JPA访问数据库

JPA是Java Persistence API的简写,是官网提出的一种ORM标准! JPA标准,都在包门路:javax.persistence.*下,像一些罕用的如:@Entity、@Id及@Transient都在此门路下。这些也是一些当初市面上罕用的ORM一些约定俗成的注解了。 Spring Data JPA是Spring基于Hibernate开发的一个JPA框架。能够极大的简化JPA的写法,能够在简直不必写具体代码的状况下,实现对材料的拜访和操作。除了「CRUD」外,还包含如分页、排序等一些罕用的性能。 pom.xml中增加依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId></dependency>application.properties 配置spring.datasource.url=jdbc:mysql://localhost:3306/rumenz_springbootspring.datasource.username=rootspring.datasource.password=root1234spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.jpa.hibernate.ddl-auto=updatespring.sql.init.mode=alwaysspring.sql.init.schema-locations=classpath:/ddl/user-book.sqlspring.sql.init.data-locations=classpath:/ddl/user-book-data.sqlspring.jpa.hibernate.ddl-auto 是否依据实体类更新数据库,有四个属性值属性值作用create每次加载hibernate时都会删除上一次的生成的表,而后依据你的model类再从新来生成新表,哪怕两次没有任何扭转也要这样执行,这就是导致数据库表数据失落的一个重要起因。create-drop每次加载hibernate时依据model类生成表,然而sessionFactory一敞开,表就主动删除。update最罕用的属性,第一次加载hibernate时依据model类会主动建设起表的构造(前提是先建设好数据库),当前加载hibernate时依据 model类自动更新表构造,即便表构造扭转了但表中的行依然存在不会删除以前的行。要留神的是当部署到服务器后,表构造是不会被马上建设起来的,是要等利用第一次运行起来后才会。validate每次加载hibernate时,验证创立数据库表构造,只会和数据库中的表进行比拟,不会创立新表,然而会插入新值。spring.sql.init.mode 是否应用sql文件初始化数据库,有3个值属性值作用ALWAYS始终初始化数据库。EMBEDDED仅初始化嵌入式数据库。NEVER永远不要初始化数据库。spring.sql.init.schema-locations 指定建表的sql文件spring.sql.init.data-locations指定数据sql文件创立实体类User.java@Getter@Setter@Builder@AllArgsConstructor@Entity //jpa必填@DynamicInsert //填充默认值@DynamicUpdate //填充默认值@Table(name = "user") //jpa必填@NoArgsConstructorpublic class User { @Id //jpa必填 @GeneratedValue(strategy = GenerationType.IDENTITY) //jpa必填 private Integer id; private String name; private String domain; @Column(name = "age",columnDefinition = "tinyint default 0") private Integer age;}@GeneratedValue(strategy = GenerationType.IDENTITY)有以下几种类型TABLE:应用一个特定的数据库表格来保留主键。SEQUENCE:依据底层数据库的序列来生成主键,条件是数据库反对序列。IDENTITY:主键由数据库主动生成(次要是主动增长型)AUTO:主键由程序控制。创立repository数据长久层,负责拜访数据库,在这里申明的办法个别不必实现,只有依照Jpa的标准就能够主动生成SQL语句。package com.rumenz.lession15.controller.repository;import com.rumenz.lession15.controller.entity.User;import org.springframework.data.domain.Page;import org.springframework.data.domain.Pageable;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.data.repository.PagingAndSortingRepository;import org.springframework.stereotype.Repository;import java.util.List;import java.util.Optional;/** * @className: UserRepository * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/12/14 **/@Repositorypublic interface UserRepository extends PagingAndSortingRepository<User,Integer> { Optional<User> findById(Integer id); List<User> findDistinctUserByName(String name); Integer countUserByName(String name); List<User> readDistinctByName(String name); Page<User> findAllByName(String name, Pageable pageable);}Jpa能够通过接口名生成对应的sql语句,如 find... By,read... By,query... By,count... By,和get... By 。这些办法能够蕴含其余表达式,例如在要创立的查问上设置 Distinct 标记。第一个 By 用作分隔符,示意条件的开始,前面定义实体属性的各种条件,并将它们用 And 和 Or 连接起来。例如:interface RumenzRepository extends JpaRepository<Rumenz, Long> { List<Rumenz> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname); // 为查问启用 distinct 标记 List<Rumenz> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname); List<Rumenz> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname); // 为单个属性启用疏忽大小写 List<Rumenz> findByLastnameIgnoreCase(String lastname); // 为所有属性启用疏忽大小写 List<Rumenz> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname); // 为查问启用动态 Order by List<Rumenz> findByLastnameOrderByFirstnameAsc(String lastname); List<Rumenz> findByLastnameOrderByFirstnameDesc(String lastname);}举一些例子关键字办法示例JPQL snippetAndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2Is, EqualsfindByFirstname,findByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2LessThanfindByAgeLessThan… where x.age < ?1LessThanEqualfindByAgeLessThanEqual… where x.age <= ?1GreaterThanfindByAgeGreaterThan… where x.age > ?1GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1AfterfindByStartDateAfter… where x.startDate > ?1BeforefindByStartDateBefore… where x.startDate < ?1IsNull, NullfindByAge(Is)Null… where x.age is nullIsNotNull, NotNullfindByAge(Is)NotNull… where x.age not nullLikefindByFirstnameLike… where x.firstname like ?1NotLikefindByFirstnameNotLike… where x.firstname not like ?1StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 (parameter bound with appended %)EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 (parameter bound with prepended %)ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound wrapped in %)OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname descNotfindByLastnameNot… where x.lastname <> ?1InfindByAgeIn(Collection ages)… where x.age in ?1NotInfindByAgeNotIn(Collection ages)… where x.age not in ?1TruefindByActiveTrue()… where x.active = trueFalsefindByActiveFalse()… where x.active = falseIgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)Repository有3种 ...

February 23, 2022 · 3 min · jiezi

关于springboot:oneToMany中save-the-transient-instance-before-flushing问题的解决

save the transient instance before flushing,翻译过去就是 在刷新之前保留长期实例。 这个问题通常呈现在父子实体的存储程序上,比方物业对小区是一对多的关系那么咱们在保留数据时就应该先保留物业再更新小区,如果先更新小区的话那么他对应的物业还是属于一个长期数据也就是说物业还没有本人对应的ID,那么小区天然也就更新不了。然而这个问题通常不仅仅呈现在保留程序上,咱们来看看上面这个实例:当我想要更新小区时就会产生上述报错,报错行为第132行,这里并没有进行存储操作,并且实践上是曾经存储完了物业,再查问对应小区也不会有什么问题。 排查之后发现第132行是依据propertyCompany来查找的,而咱们保留的是newPropertyCompany,也就是说propertyCompany是没有ID的,newPropertyCompany存在ID。 所以这个问题呈现的根本原因是操作了没有ID的实体,当咱们遇到此类报错时只须要再控制台中输入一下操作实体的ID,很容易就能够排查进去。

February 23, 2022 · 1 min · jiezi

关于springboot:221汇报

问题这周遇到的问题次要是环境问题第一个就是历史遗留问题,MySQL版本问题过后没有及时解决,过后想着就是啥时候遇到问题再说,而后在跑日志零碎的时候是没有问题的,起初在智慧社区就有问题了。其实过后是没有装MySQL的,过后装了xampp,而后用的xampp内置的MySQL服务,没方法只能从新装MySQL。装完mysql遇到一个很离谱的问题,终端输出异样解决完这个又发现数据库出问题又从新批改用户名明码,从新登录解决第二个是navicat忽然用不了了,过年之前还是能够失常应用的,而后电脑就始终没开过,过完年动工发现忽然打不开了,在尝试各种办法无奈解决后抉择了另一款软件,DBeaver目前用起来感觉还不错,重点是收费,不必像navicat费心理破解或去找破解版DBeaver装置应用 nginx对于nginx在之前学thinkphp时接触过,但只是用了http server,所以对nginx齐全不晓得怎么用 什么是nginxNginx (engine x) 是一款轻量级的 Web 服务器 、反向代理服务器及电子邮件(IMAP/POP3)代理服务器。 什么是反向代理?反向代理(Reverse Proxy)形式是指以代理服务器来承受 internet 上的连贯申请,而后将申请转发给外部网络上的服务器,并将从服务器上失去的后果返回给 internet 上申请连贯的客户端,此时代理服务器对外就体现为一个反向代理服务器。 我了解的流程而在没有nginx时的流程为 在我第一次梳理完这个流程后感觉nginx有些鸡肋为什么不能间接拜访前台并由前台间接拜访后盾呢 为什么应用nginx1、爱护了实在的web服务器,web服务器对外不可见,外网只能看到反向代理服务器,而反向代理服务器上并没有实在数据,因而,保障了web服务器的资源平安。2、反向代理为根底产生了动静资源拆散以及负载平衡的形式,加重web服务器的累赘,减速了对网站访问速度3、节约了无限的IP地址资源,企业内所有的网站共享一个在internet中注册的IP地址,这些服务器调配公有地址,采纳虚拟主机的形式对外提供服务 动静资源拆散:动静拆散是让动静网站里的动静网页依据肯定规定把不变的资源和常常变的资源辨别开来,动静资源做好了拆分当前,咱们就能够依据动态资源的特点将其做缓存操作,这就是网站动态化解决的外围思路负载平衡:将工作调配到多个服务器上 常用命令nginx 启动nginx -s stop 疾速敞开Nginx,可能不保留相干信息,并迅速终止web服务。nginx -s quit 安稳敞开Nginx,保留相干信息,有安顿的完结web服务。nginx -s reload 因扭转了Nginx相干配置,须要从新加载配置而重载。nginx -s reopen 从新关上日志文件。nginx -c filename 为 Nginx 指定一个配置文件,来代替缺省的。nginx -t 不运行,而仅仅测试配置文件。nginx 将查看配置文件的语法的正确性,并尝试关上配置文件中所援用到的文件。nginx -v 显示 nginx 的版本。nginx -V 显示 nginx 的版本,编译器版本和配置参数。应用时只须要在nginx.conf中include 我的项目的nginx.conf文件即可 想理解更多nginx配置文件的信息能够参考Nginx 繁难教程 nginx配置文件详解 @JsonView简介@JsonView是Jackson的一个注解,能够用来过滤序列化对象的字段属性,是你能够抉择序列化对象哪些属性,哪些过滤掉。能够简略了解为一个过滤器,能够依据须要对实体进行进行解决,返回须要的数据,而不是整个实体 具体应用首先在实体中建设接口 // 视图1 public interface OneView{}; // 视图2 继承视图1 public interface TwoView extends OneView{};而后在get办法中退出注解 ...

February 21, 2022 · 1 min · jiezi

关于springboot:记录本周遇到的问题

一.后盾单元测试中run,和debug模式测试后果不同 目前测试controller控制器下update办法的流程图 目前问题出在参数捕捉上。在debug模式下,当我用一行行执行上来的时候,执行到上面第二行entityArgumentCaptor.getValue()的时候测试报错说并没有捕捉到数据。 1 Mockito.verify(this.Service).update(longArgumentCaptor.capture(), entityArgumentCaptor.capture());2 Assertions.assertEquals(oldEntity.getName(), entityArgumentCaptor.getValue().getName());来看看报错 它说参数没有捕捉,可能是因为两个起因。1.可能没有verify()中应用argument.captrue()。2.可能在某个桩中应用的capture(),然而没有被调用。并举荐只在 verify()中应用capture()。 最初还贴心地给出例子: 然而和上述代码一比拟就发现用法齐全和举荐的统一。 而后又试着间接用run模式测试,后果居然通过了。 最初测试了很久,报错起因是我没有把verify()里的两个参数写在同一行,如图204行和205行 在我没有把参数写在同一行的时候,debug模式下,点下一步,跳到204行,接着跳到205行,而后不知为何又跳回204行。而204行只有id的参数捕捉。 通过测试,两个捕捉器都没有捕捉到参数。 猜想可能是因为debug是一行一行地执行语句,当不把参数写在同一行时,执行就可能出错,语句间接失败。 之后把参数放在同一行之后,debug模式下执行后果正确。 二.jpa参数不容许为null情景:查问参数name 为空时显示所有数据,前台向后盾传了查问条件name为null在测试的时候发现报错 jpa定义的查问 Page<PropertyCompany> findAllByNameContainingAndDeletedIsFalse(String name, Pageable pageable);起因:jpa的findByXXX 参数不容许为null。 解决办法:1:service层加判断,为null时设置为空字符串。 public Page<PropertyCompany> page(String name, @NotNull Pageable pageable) { if (name == null) { name = ""; }2.自定义查问: default Page<PropertyCompany> findAll(String name, @NotNull Pageable pageable) { Specification<PropertyCompany> specification = PropertyCompanySpecs.containingName(name); return this.findAll(specification, pageable); }public class PropertyCompanySpecs { public static Specification<PropertyCompany> containingName(String name) { if (name != null && !name.trim().isEmpty()) { return (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.like(root.get("name").as(String.class), String.format("%%%s%%", name.trim())); } else { return Specification.where(null); } }}如果的确想要查问name为null的字段怎么办? ...

February 21, 2022 · 1 min · jiezi

关于springboot:第十四节SpringBoot使用JdbcTemplate访问操作数据库基本用法

Spring对数据库的操作在jdbc下面做了深层次的封装,应用spring的注入性能,能够把DataSource注册到JdbcTemplate之中。 JdbcTemplate在Spring-jdbc包上面,还须要Spring-tx包反对,外面蕴含事务和异样管制. 建一个rumenz_springboot库创立user表create table user( id int primary key auto_increment, name varchar(100) not null default '', domain varchar(100) not null default '')engine=innodb default charset=utf8;退出pom的依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope></dependency>SpringBoot配置文件application.propertiesspring.datasource.url=jdbc:mysql://localhost:3306/rumenz_springbootspring.datasource.username=rootspring.datasource.password=root1234spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver创立User实体类@Builder@Data@AllArgsConstructorpublic class User implements RowMapper { private Integer id; private String name; private String domain; @Override public Object mapRow(ResultSet rs, int rowNum) throws SQLException { User user=new User(); user.setId(rs.getInt("id")); user.setName(rs.getString("name")); user.setDomain(rs.getString("domain")); return user; }}Service接口UserService.javapackage com.rumenz.lession14.controller.service;import com.rumenz.lession14.controller.entity.User;import java.util.List;/** * @className: UserService * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/12/13 **/public interface UserService { Integer save(User user); List<User> list(); Integer update(User user); Integer batchSave();}Service接口实现类UserServiceImpl.javapackage com.rumenz.lession14.controller.service.Impl;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.databind.json.JsonMapper;import com.rumenz.lession14.controller.entity.User;import com.rumenz.lession14.controller.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.BeanPropertyRowMapper;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Service;import java.util.ArrayList;import java.util.List;/** * @className: UserServiceImpl * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/12/13 **/@Servicepublic class UserServiceImpl implements UserService { @Autowired private JdbcTemplate jdbcTemplate; @Override public Integer save(User user) { int reint = jdbcTemplate.update("insert into user(name,domain) values (?,?)", user.getName(), user.getDomain()); return reint; } @Override public Integer batchSave() { String sql="insert into user(name,domain) values(?,?)"; List<Object[]> par=new ArrayList<>(); for (int i = 0; i < 10; i++) { String[] s=new String[2]; s[0]="入门小站"+i; s[1]="https://rumenz.com/"+i; par.add(s); } int[] ints = jdbcTemplate.batchUpdate(sql, par); System.out.println(ints.toString()); return 0; } @Override public List<User> list() { //User实现RowMapper接口,实现接口里的mapRow办法。 List<User> list = jdbcTemplate.query("select * from user",new User()); return list; } @Override public Integer update(User user) { Integer reint=jdbcTemplate.update("update user set name=?,domain=? where id=?", user.getName(),user.getDomain(),user.getId()); // return reint; }}Controller测试RumenzController.javapackage com.rumenz.lession14.controller;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import com.rumenz.lession14.controller.entity.User;import com.rumenz.lession14.controller.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.List;/** * @className: RumenzController * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/12/13 **/@RestController@RequestMapping("/rumenz")public class RumenzController { @Autowired private UserService userService; //增加数据 @GetMapping("/save") public String save(){ User user=User.builder().name("入门小站").domain("https://rumenz.com").build(); Integer reint = userService.save(user); return reint.toString(); } //批量增加数据 @GetMapping("/batchSave") public String batchSave(){ Integer reint = userService.batchSave(); return reint.toString(); } //查问数据 @GetMapping("/list") public String list() throws JsonProcessingException { List<User> list = userService.list(); ObjectMapper objectMapper=new ObjectMapper(); String val = objectMapper.writeValueAsString(list); return val; } //更新数据 @GetMapping("/update") public String update() throws JsonProcessingException { User user=User.builder().id(1).name("入门小站-批改").domain("https://tooltt.com").build(); Integer reint = userService.update(user); return reint.toString(); }}总结罕用CURD操作大抵应用以下三个办法:1.execute办法,用于间接执行SQL语句2.update办法,用户新增批改删除操作3.query办法,用于查询方法本小结源码地址:GitHub:https://github.com/mifunc/spr...Gitee:https://gitee.com/rumenz/spri...https://rumenz.com/rumenbiji/...介绍我的博客 https://rumenz.com/ ,我的工具箱 https://tooltt.com/微信公众号:【入门小站】 ...

February 21, 2022 · 2 min · jiezi

关于springboot:SpringBoot自定义classloader加密保护class文件

背景最近针对公司框架进行要害业务代码进行加密解决,避免通过jd-gui等反编译工具可能轻松还原工程代码,相干混同计划配置应用比较复杂且针对springboot我的项目问题较多,所以针对class文件加密再通过自定义的classloder进行解密加载,此计划并不是相对平安,只是加大反编译的艰难水平,防小人不防君子,整体加密爱护流程图如下图所示 maven插件加密应用自定义maven插件对编译后指定的class文件进行加密,加密后的class文件拷贝到指定门路,这里是保留到resource/coreclass下,删除源class文件,加密应用的是简略的DES对称加密 @Parameter(name = "protectClassNames", defaultValue = "") private List<String> protectClassNames; @Parameter(name = "noCompileClassNames", defaultValue = "") private List<String> noCompileClassNames; private List<String> protectClassNameList = new ArrayList<>(); private void protectCore(File root) throws IOException { if (root.isDirectory()) { for (File file : root.listFiles()) { protectCore(file); } } String className = root.getName().replace(".class", ""); if (root.getName().endsWith(".class")) { //class筛选 boolean flag = false; if (protectClassNames!=null && protectClassNames.size()>0) { for (String item : protectClassNames) { if (className.equals(item)) { flag = true; } } } if(noCompileClassNames.contains(className)){ boolean deleteResult = root.delete(); if(!deleteResult){ System.gc(); deleteResult = root.delete(); } System.out.println("【noCompile-deleteResult】:" + deleteResult); } if (flag && !protectClassNameList.contains(className)) { protectClassNameList.add(className); System.out.println("【protectCore】:" + className); FileOutputStream fos = null; try { final byte[] instrumentBytes = doProtectCore(root); //加密后的class文件保留门路 String folderPath = output.getAbsolutePath() + "\\" + "classes"; File folder = new File(folderPath); if(!folder.exists()){ folder.mkdir(); } folderPath = output.getAbsolutePath() + "\\" + "classes"+ "\\" + "coreclass" ; folder = new File(folderPath); if(!folder.exists()){ folder.mkdir(); } String filePath = output.getAbsolutePath() + "\\" + "classes" + "\\" + "coreclass" + "\\" + className + ".class"; System.out.println("【filePath】:" + filePath); File protectFile = new File(filePath); if (protectFile.exists()) { protectFile.delete(); } protectFile.createNewFile(); fos = new FileOutputStream(protectFile); fos.write(instrumentBytes); fos.flush(); } catch (MojoExecutionException e) { System.out.println("【protectCore-exception】:" + className); e.printStackTrace(); } finally { if (fos != null) { fos.close(); } if(root.exists()){ boolean deleteResult = root.delete(); if(!deleteResult){ System.gc(); deleteResult = root.delete(); } System.out.println("【protectCore-deleteResult】:" + deleteResult); } } } } } private byte[] doProtectCore(File clsFile) throws MojoExecutionException { try { FileInputStream inputStream = new FileInputStream(clsFile); byte[] content = ProtectUtil.encrypt(inputStream); inputStream.close(); return content; } catch (Exception e) { throw new MojoExecutionException("doProtectCore error", e); } }注意事项 ...

February 19, 2022 · 4 min · jiezi

关于springboot:SpringBoot自定义mavenplugin插件整合asm代码插桩

背景公司开发框架减少了web零碎license受权证书校验模块,履行一台机器一个受权证书,初步计划是减少拦截器针对全局申请进行拦挡校验,评估后认为校验形式繁多,应该减少重要工具类,业务service实现中每个办法的进行校验,因为波及代码量较大硬编码工作艰难,故抉择通过自定义maven插件在编译期间进行动静代码插桩操作 我的项目配置新建maven我的项目设置打包形式 <packaging>maven-plugin</packaging>减少依赖项 <!--应用doc的形式--> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-plugin-api</artifactId> <version>3.5.2</version> </dependency> <!--应用注解的形式--> <dependency> <groupId>org.apache.maven.plugin-tools</groupId> <artifactId>maven-plugin-annotations</artifactId> <version>3.5.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-project</artifactId> <version>2.2.1</version> </dependency> <dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>9.0</version> </dependency>build内容配置 <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-plugin-plugin</artifactId> <version>3.5</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.6.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins>编译拦挡创立编译操作类FramePlugin,继承AbstractMojo并应用Mojo注解标注,output参数是class文件编译后门路 @Mojo(name = "deepcompile", defaultPhase = LifecyclePhase.COMPILE)public class FramePlugin extends AbstractMojo { @Parameter(name = "output", defaultValue = "${project.build.directory}") private File output; public void execute() throws MojoExecutionException { File f = ; if (!f.exists()) { f.mkdirs(); } try { insertPile(f); } catch (Exception e) { exceptioncount++; e.printStackTrace(); } }ASM插桩新建ClassVisitor重写visitMethod办法来过滤拜访须要插桩的办法,须要排除自带的init办法 ...

February 19, 2022 · 2 min · jiezi

关于springboot:springboot自动装配

springboot与spring相比,有一个劣势就是大部分配置都有一套默认设定,不用再写大量的配置文件,即“约定优于配置”。而这是靠主动拆卸实现的。 一、主动加载入口springboot的启动形式如下: @SpringBootApplicationpublic class SpringRunner { public static void main(String[] args) { SpringApplication.run(SpringRunner.class, args); }}察看@SpringBootApplication注解 // ## 此注解非常重要@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {...}// ## 此注解同样重要@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {...}从下面的代码看出,最终会通过@Import注解进入AutoConfigurationImportSelector类(调用链:@SpringBootApplication->@EnableAutoConfiguration->@Import(AutoConfigurationImportSelector.class)) 持续察看: // == 1.AutoConfigurationImportSelector实现DeferredImportSelector接// 调用getImportGroup()办法,返回AutoConfigurationGroup类public class AutoConfigurationImportSelector implements DeferredImportSelector{ @Override public Class<? extends Group> getImportGroup() { return AutoConfigurationGroup.class; }}// == 2.实现DeferredImportSelector.Group接口 private static class AutoConfigurationGroup implements DeferredImportSelector.Group{..}}Group接口有两个办法: // 加载配置信息void process(AnnotationMetadata metadata, DeferredImportSelector selector);// 包装成Entry对象并返回Iterable<Entry> selectImports();接下来别离看一下这两个办法的实现。 ...

February 19, 2022 · 1 min · jiezi

关于springboot:深入浅出springboot学习笔记SpringBoot配置SSLhttps

本篇文章次要内容:SpringBoot配置SSL(https) SpringBoot全局异样解决 SpringBoot 404页面解决 接下来让咱们一起探讨三大框架之一的springboot框架: SpringBoot配置SSL(https)SpringBoot能够通过在application.properties或application.yml配置文件中配置各种server.ssl.*属性来申明性应用SSL(https),比方上面的例子在application.properties中设置SSL属性:如果应用了下面的配置就示意springboot应用程序不再在端口8080上反对HTTP连贯申请,SpringBoot不能通过配置application.properties来实现既反对HTTP连贯又反对HTTPS连贯,这是做不到的,如果要同时反对HTTP和HTTPS,则须要以编程形式配置其中的一个,倡议应用application.properties文件来配置HTTPS,以编程形式配置HTTP,这是比拟容易的办法; SpringBoot反对配置https具体步骤:1、生成证书,能够使自签名证书(平时测试的时候)或者从SSL证书受权核心购买证书(上线); 平时生成证书进行测试的话,有两种生成证书的形式 (1)利用JDK工具生成证书 证书生成后咱们能够验证下jks是否蕴含了残缺的证书链: keytool -list -v -keystore server.jkskeytool -list -v -keystore server.pkcs12(2)利用Openssl工具生成证书 通过openssl来生成,如果linux中没有装置openssl,须要装置一下,执行: yum install openssl openssl-devel -y1、#生成一个RSA密钥 (私钥) openssl genrsa -out server.key 20482、#生成一个证书申请 openssl req -new -key server.key -out server.csr -subj "/C=CN/ST=Beijing/L=Beijing/O=power Inc./OU=Web Security/CN=power.com"3、#本人签发证书 openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt字段解读 C字段:Country,单位所在国家,为两位数的国家缩写,如:CN 示意中国;ST 字段:State/Province,单位所在州或省;L 字段:Locality,单位所在城市/或县区;O 字段:Organization,此网站的单位名称;OU 字段:Organization Unit,上司部门名称,也经常用于显示其余证书相干信息,如证书类型,证书产品名称或身份验证类型或验证内容等;CN 字段:Common Name,网站的域名;转换为pkcs12格局(因为在Java中应用证书,须要转换一下格局) openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.pkcs12转换为jks格局(因为在Java中应用证书,须要转换一下格局,jks是java独有的) ...

February 18, 2022 · 1 min · jiezi

关于springboot:Spring-Boot-系统学习

Spring框架发展史Spring1.x 时代 在Spring1.x时代,都是通过xml文件配置bean,随着我的项目的不断扩大,须要将xml配置分放到不同的配置文件中,须要频繁的在java类和xml配置文件中切换。 Spring2.x时代 随着JDK 1.5带来的注解反对,Spring2.x能够应用注解对Bean进行申明和注入,大大的缩小了xml配置文件,同时也大大简化了我的项目的开发。 那么,问题来了,到底是应该应用xml还是注解呢? 最佳实际: 利用的根本配置用xml,比方:数据源、资源文件等;业务开发用注解,比方:Service中注入bean等;Spring3.x到Spring4.x再到Spring5.x 从Spring3.x开始提供了Java配置形式,应用Java配置形式能够更好的了解你配置的Bean,当初咱们就处于这个时代,并且Spring4.x、Spring5.x和Spring Boot都举荐应用java配置的形式。 Spring 5.X 利用零配置开发 Spring 框架从5.x版本举荐应用注解模式来对java应用程序进行开发与配置,并且能够齐全代替原始的XML+注解模式的开发,在应用注解模式进行我的项目开发与环境配置时,Spring 框架提供了针对环境配置与业务bean开发相干注解。 注解申明Bean 注解@Component:组件 没有明确规定其角色,作用在类级别上申明以后类为一个业务组件,被Spring Ioc 容器保护;@Service:在业务逻辑层(Service 层)类级别进行申明;@Repository:在数据拜访层(dao 层) 类级别申明;@Controller:在展示层(MVC) 应用 标注以后类为一个控制器注入Bean 注解@AutoWired:Spring 官网提供注解@Inject:JSR-330 提供注解(规范制订方)@Resource:JSR-250 提供注解 以上三种注解在Set 办法或属性上申明,个别状况下通用个别开发中更习惯申明在属性上,代码简洁清晰。基于5.x 注解配置形式简化了xml 配置,利用程序开发与xml 环境配置均通过相应注解来实现。 Spring5.x 中配置与获取Bean注解 @Configuration:作用与类上,将以后类申明为一个配置类,相当于一个xml 配置文件 @ComponentScan:主动扫描指定包下标注有@Repository,@Service,@Controller @Component:注解的类并由Ioc 容器进行实例化和保护 @Bean::作用于办法上,相当于xml 文件中<bean> 申明以后办法返回值为一个bean @Value:获取properties 文件指定key value值 实例1-Ioc中Bean的实例化与获取创立Spring 一般工程并增加坐标相干配置<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.3.RELEASE</version> </dependency></dependencies><build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf-8</encoding> </configuration> </plugin> </plugins></build>增加源代码创立UserDao ,UserService Bean 对象// UserDao.java@Repositorypublic class UserDao { public void test(){ System.out.println("UserDao.test..."); }}// UserService.java@Servicepublic class UserService { @Resource private UserDao userDao; public void test(){ System.out.println("UserService.test..."); userDao.test(); }}创立IocConfig配置类// Ioc 容器配置 Java 代码实现@Configuration@ComponentScan("com.xxxx.springboot")public class IocConfig {}创立启动类执行测试public class Starter { public static void main(String[] args) { AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext(IocConfig.class); UserService userService= ac.getBean(UserService.class); userService.test(); }} 此时启动Spring Ioc 容器通过实例化AnnotationConfigApplicationContext类,接管配置参数类IocConfig,并获取UserService Bean 实现办法调用,此时应用环境不存在xml配置文件,简化了利用的xml 配置。 ...

February 16, 2022 · 6 min · jiezi

关于springboot:第十二节Springboot多环境配置

开发的阶段会须要设定根本的属性或是自定义的属性,而且通常会被利用和装置到几个不同的环境上,比方:开发(dev)、测试(test)、生产(prod)等,其中对应的每个环境的数据库地址、服务器端口等等配置都会不同,如果在为不同环境打包时都要频繁批改配置文件的话,那必将是个十分繁琐且容易产生谬误。 通常有上面两种配置形式 1.maven的多环境配置在没有应用过Spring Boot的多环境配置时,是用maven的profile性能进行多环境配置。 maven配置pom.xml <profiles> <profile> <id>dev</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <pom.port>8080</pom.port> </properties> </profile> <profile> <id>test</id> <properties> <pom.port>8888</pom.port> </properties> </profile></profiles><build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*</include> </includes> </resource> <resource> <directory>${project.basedir}/src/main/resources</directory> <includes> <include>**/*.properties</include> </includes> <filtering>true</filtering> </resource> </resources> <plugins> <!--这个很重要--> <plugin> <artifactId>maven-resources-plugin</artifactId> <configuration> <encoding>utf-8</encoding> <!-- 须要退出,因为maven预设的是${},而springbooot 预设会把此替换成@{} --> <useDefaultDelimiters>true</useDefaultDelimiters> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins></build>application.properties的配置server.port=${pom.port}编译打包我的项目> mvn clean install -DskipTests -Ptest-Ptest示意编译为测试环境,对应<profile>下的<id>test</id>2.SpringBooot的多环境配置在Spring Boot中多环境配置文件名须要满足application-{profile}.properties的格局,其中{profile}对应你的环境标识。application-dev.properties:开发环境application-test.properties:测试环境application-prod.properties:生产环境而决定应用哪种环境的的配置文件,须要在application.properties中通过spring.profiles.active属性来设定,其值对应{profile}值。application.properties的配置# 指定dev開發環境spring.profiles.active=devspring.profiles.active=dev 就会载入application-dev.properties 配置文件内容测试三个配置文件application-dev.properties、application-test.properties、application-prod.properties 三个文件的 server.port属性不一样, application-dev.properties server.port=8081application-test.properties server.port=8082application-prod.properties server.port=8080运行测试# 运行端口被改成8081> java -jar rumenz.jar --spring.profiles.active=dev # 运行端口被改成8082> java -jar rumenz.jar --spring.profiles.active=test# 运行端口被改成8080> java -jar rumenz.jar --spring.profiles.active=prod本小结源码地址:GitHub:https://github.com/mifunc/spr...Gitee:https://gitee.com/rumenz/spri...https://rumenz.com/rumenbiji/...我的博客 https://rumenz.com/我的工具箱 https://tooltt.com/微信公众号:【入门小站】 ...

February 16, 2022 · 1 min · jiezi

关于springboot:Spring-CloudEureka

一、 Eureka概述1.创立 eureka server 我的项目:sp05-eureka增加依赖: 2.增加pom.xml<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>cn.tedu</groupId> <artifactId>sp05-eureka</artifactId> <version>0.0.1-SNAPSHOT</version> <name>sp05-eureka</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR9</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>3.批改application.ymlspring: application: name: eureka-server server: port: 2001 eureka: server: enable-self-preservation: false instance: hostname: eureka1 client: register-with-eureka: false fetch-registry: false 参数介绍:eureka 集群服务器之间,通过 hostname 来辨别 ...

February 15, 2022 · 2 min · jiezi

关于springboot:Scheduled-定时任务

在开发中,有时候会遇到定时推送的需要,例如定时发送推送、定时发送邮件等等。SpringBoot为咱们内置了定时工作,咱们只须要一个注解就能够开启定时为咱们所用了。 开启定时工作在入口类LogApplication中增加 @EnableScheduling 注解,增加注解后SpringBoot就曾经认定了咱们要应用定时工作来实现一些业务逻辑了,外部会对应原始配置定时工作增加对应的配置文件。 @SpringBootApplication@EnableScheduling + // 启用定时工作public class LogApplication { @Scheduled配置定时工作非常简单,只须要在须要定时执行的办法上增加 @Scheduled 注解即可。留神,该类上须要打上组件型注解,例如 @Componet,这样该类才会被注入到 Spring 容器中进行治理,用来表明这是一个被Spring治理的Bean,@Scheduled 才会失效。当然个别会应用@Coponent的衍生注解:@Repository, @Service, @Controller来代替,这里不开展讲了。 @Service +public class DayLogTaskImpl implements DayLogTask { @Scheduled(cron = "* * * * * ?") + public void test1() {当初来测试一下代码: @Scheduled(cron = "* * * * * ?") public void test1() { /** * 每秒执行一次 */ logger.info("scheduler1 执行: " + System.currentTimeMillis()); }运行后果: 2022-02-14 13:46:50.000 INFO 2337 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : scheduler1 执行: 16448284100002022-02-14 13:46:51.003 INFO 2337 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : scheduler1 执行: 16448284110032022-02-14 13:46:52.000 INFO 2337 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : scheduler1 执行: 16448284120002022-02-14 13:46:53.000 INFO 2337 --- [ scheduling-1] club.yunzhi.log.task.DayLogTask : scheduler1 执行: 1644828413000能够看到打印出的工夫相隔都大概是1000毫秒左右,合乎定义的每秒执行一次。 ...

February 14, 2022 · 3 min · jiezi

关于springboot:第十一节Springboot整合log4j2日志

SpringBoot默认应用的是logback, 然而还有一个性能更高的日志实现框架log4j2.为什么选用log4j2相比与其余的日志零碎,log4j2丢数据这种状况少;disruptor技术,在多线程环境下,性能高于logback等10倍以上;利用jdk1.5并发的个性,缩小了死锁的产生; 上面是来自网络上一张性能比照图片 同步日志模式下, Logback的性能是最蹩脚的,log4j2的性能无论在同步日志模式还是异步日志模式下都是最佳的 log4j2性能高的次要起因是它用了一个LMAX无锁的线程间通信库. pom.xml中引入log4j2<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions><!-- 去掉springboot默认配置 --> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions></dependency><dependency><!-- 引入log4j2依赖 --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> <version>1.4.7.RELEASE</version></dependency>log4j2的配置文件默认名log4j2-spring.xml. 如果是其它的名字须要在配置文件中指定logging.config=xxx.xml配置文件模版<?xml version="1.0" encoding="UTF-8"?><!--Configuration前面的status,这个用于设置log4j2本身外部的信息输入,能够不设置,当设置成trace时,你会看到log4j2外部各种具体输入--><!--monitorInterval:Log4j可能自动检测批改配置 文件和重新配置自身,设置距离秒数--><configuration monitorInterval="5"> <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <!--变量配置--> <Properties> <!-- 格式化输入:%date示意日期,%thread示意线程名,%-5level:级别从左显示5个字符宽度 %msg:日志音讯,%n是换行符--> <!-- %logger{36} 示意 Logger 名字最长36个字符 --> <property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" /> <!-- 定义日志存储的门路 --> <property name="FILE_PATH" value="更换为你的日志门路" /> <property name="FILE_NAME" value="更换为你的我的项目名" /> </Properties> <appenders> <console name="Console" target="SYSTEM_OUT"> <!--输入日志的格局--> <PatternLayout pattern="${LOG_PATTERN}"/> <!--控制台只输入level及其以上级别的信息(onMatch),其余的间接回绝(onMismatch)--> <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> </console> <!--文件会打印出所有信息,这个log每次运行程序会主动清空,由append属性决定,适宜长期测试用--> <File name="Filelog" fileName="${FILE_PATH}/test.log" append="false"> <PatternLayout pattern="${LOG_PATTERN}"/> </File> <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会主动存入按年份-月份建设的文件夹上面并进行压缩,作为存档--> <RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz"> <!--控制台只输入level及以上级别的信息(onMatch),其余的间接回绝(onMismatch)--> <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="${LOG_PATTERN}"/> <Policies> <!--interval属性用来指定多久滚动一次,默认是1 hour--> <TimeBasedTriggeringPolicy interval="1"/> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始笼罩--> <DefaultRolloverStrategy max="15"/> </RollingFile> <!-- 这个会打印出所有的warn及以下级别的信息,每次大小超过size,则这size大小的日志会主动存入按年份-月份建设的文件夹上面并进行压缩,作为存档--> <RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log" filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz"> <!--控制台只输入level及以上级别的信息(onMatch),其余的间接回绝(onMismatch)--> <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="${LOG_PATTERN}"/> <Policies> <!--interval属性用来指定多久滚动一次,默认是1 hour--> <TimeBasedTriggeringPolicy interval="1"/> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始笼罩--> <DefaultRolloverStrategy max="15"/> </RollingFile> <!-- 这个会打印出所有的error及以下级别的信息,每次大小超过size,则这size大小的日志会主动存入按年份-月份建设的文件夹上面并进行压缩,作为存档--> <RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz"> <!--控制台只输入level及以上级别的信息(onMatch),其余的间接回绝(onMismatch)--> <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="${LOG_PATTERN}"/> <Policies> <!--interval属性用来指定多久滚动一次,默认是1 hour--> <TimeBasedTriggeringPolicy interval="1"/> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始笼罩--> <DefaultRolloverStrategy max="15"/> </RollingFile> </appenders> <!--Logger节点用来独自指定日志的模式,比方要为指定包下的class指定不同的日志级别等。--> <!--而后定义loggers,只有定义了logger并引入的appender,appender才会失效--> <loggers> <!--过滤掉spring和mybatis的一些无用的DEBUG信息--> <logger name="org.mybatis" level="info" additivity="false"> <AppenderRef ref="Console"/> </logger> <!--监控零碎信息--> <!--若是additivity设为false,则 子Logger 只会在本人的appender里输入,而不会在 父Logger 的appender里输入。--> <Logger name="org.springframework" level="info" additivity="false"> <AppenderRef ref="Console"/> </Logger> <root level="info"> <!--定义日志级别,大于等于info级别的日志都将被输入--> <appender-ref ref="Console"/> <appender-ref ref="Filelog"/> <appender-ref ref="RollingFileInfo"/> <appender-ref ref="RollingFileWarn"/> <appender-ref ref="RollingFileError"/> </root> </loggers></configuration>configurationstatus用来指定log4j自身的打印日志的级别.monitorInterval 通过monitorInterval这个配置参数能够动静监测配置文件是否批改了,如果批改了,依照最新的配置文件,比方能够动静批改logger的优先级Properties变量定义property 定义一个变量,如下格局<!-- 格式化输入:%date示意日期,%thread示意线程名,%-5level:级别从左显示5个字符宽度 %msg:日志音讯,%n是换行符--><!-- %logger{36} 示意 Logger 名字最长36个字符 --><property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />appendersconsole 定义输入到控制台的Appender//子元素name:指定Appender的名字.target:SYSTEM_OUT 或 SYSTEM_ERR,个别只设置默认:SYSTEM_OUT.PatternLayout:输入格局,不设置默认为:%m%n.ThresholdFilter: `<!--控制台只输入level(属性)及以上级别的信息(onMatch),其余的间接回绝(onMismatch)-->`File 用来定义输入到指定地位文件的AppenderRollingFile 定义超过指定条件日志的删除和新建策略name:指定Appender的名字.fileName:指定输入日志的目标文件带全门路的文件名.PatternLayout:输入格局,不设置默认为:%m%n.filePattern:指定新建日志文件的名称格局.Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输入日志,子元素`TimeBasedTriggeringPolicy interval="1" `interval属性用来指定多久滚动一次,默认是1 hour。`SizeBasedTriggeringPolicy size="10MB"`,size属性用来定义每个日志文件的大小。loggerslogger 用来独自指定日志格局Root 用来指定我的项目的根日志,如果没有独自指定Logger,那么就会默认应用该Root日志输入. ...

February 14, 2022 · 2 min · jiezi

关于springboot:消息中间件入门

1、什么是消息中间件利用高效牢靠的消息传递机制进行平台无关的数据交换; 并基于数据通信来进行分布式系统的集成; 通过提供消息传递和音讯排队模型,它能够在分布式环境下扩大过程间的通信; 2、消息中间件的利用场景跨零碎数据传递、高并发流量削峰、数据异步解决…等等3、罕用的消息中间件ActiveMQ、RabbitMQ、Kafka、RocketMQ4、消息中间件设计思维协定、长久化机制、音讯散发策略、高可用、高牢靠5、协定是什么协定是计算机之间通信时独特听从的一组约定,都恪守雷同的约定,计算机之间能力互相交换。协定是计算机之间通信时独特听从的一组约定,都恪守雷同的约定,计算机之间能力互相交换。 协定三要素: 语法:即数据与管制信息的构造或格局;语义:即须要收回何种管制信息,实现何种动作以及做出何种响应; 时序(同步):即事件实现程序的具体阐明 消息中间件罕用的协定:OpenWire、AMQP、MQTT、Kafka、OpenMessage MQTT协定(RabbiMQ、ActiveMQ):MQTT (Message Queuing Telemetry Transport)音讯队列遥测传输是IBM开发的一个即时通讯协定,物联网零碎架构中的重要组成部分。 个性:轻量、构造简略、传输快、没有事务反对、没有长久化相干设计 利用场景:实用于计算能力无限、低带宽、网络不稳固的场景。 Open Message协定(RocketMQ)OpenMessaging是近一两年由阿里发动,与雅虎、滴滴出行、Streamlio等公司独特参加创建的分布式消息中间件、流解决畛域的利用开发规范。是国内首个在寰球范畴内发动的分布式音讯畛域国内准。个性:构造简略、解析快、有事务设计、有长久化设计 Kafka协定(kafka)Kafka协定是基于TCP的二进制协定。音讯外部是通过长度来分隔,由一些根本数据类型组成。个性:构造简略、解析快、无事务设计、有长久化设计 6、罕用长久化形式 ActiveMQRabbitMQKafkaRocketMQ文件系统反对反对反对反对数据库反对///7、罕用的消息中间件散发策略 ActiveMQRabbitMQKafkaRocketMQ公布订阅反对反对反对反对轮询散发反对反对反对/偏心散发/反对反对/重发反对反对/反对音讯拉取/反对反对反对8、高可用机制高可用性是指产品在规定的条件和规定的时刻或工夫区间内处于可执行规定性能状态的能力。 当业务量大时,一台消息中间件服务器可能无奈满足需要,所以须要消息中间件可能集群部署,来达到高可用的目标。 Master-Slave主从共享数据的部署形式 Master-Slave主从同步部署形式 Broker-Cluster多主集群同步部署形式 Broker-Cluster多主集群转发部署形式 Master-Slave与Broker-Cluster联合 9、高牢靠是什么高可靠性是指零碎能够无故障地继续运行。比方一个零碎从来不解体、报错,或者解体、报错的几率较低,那就是高牢靠。在高并发业务场景下,如果不能保证系统的高牢靠,那造成的损失将会十分重大。保障消息中间件的高可靠性,能够从以下几方面思考 音讯传输牢靠:通过协定来保证系统间数据解析的正确性。 音讯存储牢靠:通过长久化来保障音讯的存储可靠性。

February 12, 2022 · 1 min · jiezi

关于springboot:第十节SpringBoot中的日志管理

SpringBoot默认应用的日志框架是logback 。spring-boot-starter中蕴含了spring-boot-starter-logging模块。该日志框架就是logback。所以咱们也不须要独自引入spring-boot-starter-logging模块。<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId></dependency>SpringBoot默认日志格局 格局阐明工夫戳,准确到毫秒:2021-11-13 14:35:20.298logback日志级别.日志级别分为:TRACE、DEBUG、INFO、WARN、ERROR、FATAL:INFO过程ID:1414宰割符:默认是:---线程名称:[ restartedMain]案例演示这里咱们用到了lombok,应用日志的时候咱们能够用@Slf4j注解。 pom.xml配置<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.6</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.rumenz</groupId> <artifactId>lession10</artifactId> <version>0.0.1-SNAPSHOT</version> <name>lession10</name> <description>第十节:SpringBoot中的日志治理</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>咱们在Controller打印日志package com.rumenz.lession10.controller;import lombok.extern.slf4j.Slf4j;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * @className: RumenzController * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/11/11 **/@Slf4j //lombok 提供的注解@RestController@RequestMapping("/rumenz")public class RumenzController { //如果不应用lombok就须要用以下代码获取日志操作对象 //Logger log = LoggerFactory.getLogger(RumenzController.class); @GetMapping("/index") public String index(){ log.trace("Trace 日志..."); log.debug("Debug 日志..."); log.info("Info 日志..."); log.warn("Warn 日志..."); log.error("Error 日志..."); return "入门小站"; }}启动Lession10Application,浏览器拜访http://127.0.0.1:8080/rumenz/index查看控制台 ...

February 12, 2022 · 1 min · jiezi

关于springboot:wgcloudserver程序未启动这个是什么意思

这个可能是linux主机没有设置JDK1.8环境变量或者server/config/application.yml有谬误,个别是配置项冒号后没有保留一个空格导致的,因为yml文件规定就是冒号后保留一个空格,然而大家容易疏忽这个细节 最初能够这样测试下,这样会输入具体的错误信息java -jar wgcloud-server-release.jar WGCLOUD是一款轻量高性能的运维管理软件,具备自动化、分布式、部署上手简略等特点 WGCLOUD的github仓库地址:https://github.com/tianshiyeb...码云仓库地址:https://gitee.com/wanghouhou/...

February 10, 2022 · 1 min · jiezi

关于springboot:对接企业微信回调时orgapachecommonscodecbinaryBase64导入失败

依据官网的提醒和网上的教程,我新增了一个wechataes文件夹,并批改了package。然而import org.apache.commons.codec.binary.Base64里的commons始终爆红。返回企业微信api文档,也发现强调了这个包:https://developer.work.weixin... 然而不晓得进去下载了压缩包要怎么解决,故又去寻找解决方案。起初找到篇文章:https://www.cnblogs.com/telwa... 外面说下载一个Pom包即可解决,尝试后果然能够。 pom包的链接:https://mvnrepository.com/art...

February 10, 2022 · 1 min · jiezi

关于springboot:第九节SpringBoot在线文档Swagger2入门

Swagger2 是一个开源我的项目,用于为 RESTful Web 服务生成 REST API 文档。它提供了一个用户界面,能够通过 Web 浏览器拜访咱们的 RESTful Web 服务,测试接口。SpringBoot集成Swagger2 3.0以下版本pom.xml<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version></dependency><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version></dependency>Swagger2Config配置文件package com.rumenz.lession9.controller.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.service.Contact;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2;/** * @className: Swagger2Config * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/11/10 **/@Configuration@EnableSwagger2 //Swagger2 3.0以下版本须要开启的注解public class Swagger2Config { @Bean public Docket docket(){ return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.rumenz.lession9.controller")) .paths(PathSelectors.any()).build(); } private ApiInfo apiInfo(){ Contact contact=new Contact("入门小站", "https://rumenz.com", "xenry@163.com"); return new ApiInfoBuilder() .title("入门小站接口文档") .description("https://rumenz.com") .contact(contact).build(); }}3.0以下开启@EnableSwagger2这个注解 ...

February 10, 2022 · 2 min · jiezi

关于springboot:第八节SpringBoot指定配置文件配置三

SpringBoot配置属性的规定通过.拆散各个元素最初一个.将前缀与属性名称离开必须是字母(az)和数字(0-9)必须是小写字母用连字符-来分隔单词惟一容许的其余字符是[和],用于List的索引不能以数字结尾雷同的配置项Spring Boot 2.x 加载配置文件的时候会移除特殊字符并且还会将配置均用全小写的形式进行匹配和加载。 application.properties com.rumenz.id-name=rumenzcom.rumenz.id_name=rumenzcom.rumenz.idName=rumenzcom.rumenz.idname=rumenz测试package com.rumenz.lession8.controller;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;/** * @className: RumenzController * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/11/8 **/@Controller@RequestMapping("/rumenz")public class RumenzController { @Value("${com.rumenz.idname}") private String comRumenzIdName; @RequestMapping("/index") @ResponseBody public String index(){ return comRumenzIdName; }}浏览器拜访http://127.0.0.1:8080/rumenz/index,返回rumenz 以上4个配置项是等价的,举荐全小写两头用-宰割。 配置文件的优先级application.properties和application.yml文件能够在放在以下几个地位。内部:利用程序运行目录的config子目录内部:利用程序运行目录的跟目录外部:在config包外面classpath:/config/外部:在classpath根目录classpath:/门路参数值/springboot-zhinan/lession8/config/application.propertiescom.rumenz.level=1/springboot-zhinan/lession8/application.propertiescom.rumenz.level=2/springboot-zhinan/lession8/src/main/resources/config/application.propertiescom.rumenz.level=3/springboot-zhinan/lession8/src/main/resources/application.propertiescom.rumenz.level=4 application.properties中配置了com.rumenz.levelcom.rumenz.level=1测试package com.rumenz.lession8.controller;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;/** * @className: RumenzController * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/11/8 **/@Controller@RequestMapping("/rumenz")public class RumenzController { @Value("${com.rumenz.idname}") private String comRumenzIdName; @Value("${com.rumenz.level}") private String comRumenzLevel; @RequestMapping("/index") @ResponseBody public String index(){ return comRumenzIdName; } @RequestMapping("/index1") @ResponseBody public String index1(){ return comRumenzLevel; }}应用mvn clean package打包后,应用jar -jar lession8-0.0.1-SNAPSHOT.jar运行。如果上述4个中央都定义了application.properties,并且都配置了com.rumenz.level ,当咱们的业务外面须要用com.rumenz.level配置项。查找的优先级是:1.先找运行目录下的config的application.properties中的com.rumenz.level,找到返回,否则下一步2.再找运行目录下的application.properties中的com.rumenz.level,找到返回否则下一步3.再找classpath下的config目录的application.properties的com.rumenz.level,找到返回否则下一步4.再找classpath下的application.properties的com.rumenz.level,找到就返回,找不到就报错,我的项目启动失败。命令行参数配置springboot的application.properties中能够配置一些参数,如端口号,账号,明码。如果咱们想在运行的时候想长期批改运行的端口也是能够的。java -jar lession8-0.0.1-SNAPSHOT.jar --server.port=9000这样我的项目运行的端口就变成了9000,--server.port=9000相当于在application.properties中配置server.port=9000零碎环境变量咱们也能够在操作系统外面定义变量,而后通过@Value注入到Spring容器中。package com.rumenz.lession8.controller;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;/** * @className: RumenzController * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/11/8 **/@Controller@RequestMapping("/rumenz")public class RumenzController { //读取零碎环境变量 @Value("${PATH}") private String path; @RequestMapping("/index2") @ResponseBody public String index2(){ return path; } }浏览器拜访http://127.0.0.1:8080/rumenz/index2,返回/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/usr/local/share/dotnet:~/.dotnet/tools:/usr/local/mysql/bin:/usr/local/mysql/bin零碎属性咱们能够设置VM arguments向Spring容器传递参数值。Idea中设置VM arguments ...

February 8, 2022 · 1 min · jiezi

关于springboot:聊聊如何修复springboot使mavenresourcesplugin占位符失效问题

前言之前咱们在聊聊如何进行代码混同这篇文章提到,在springboot我的项目应用allatori,有一个小坑。这个坑就是当你在allatori.xml配置 <input> <jar in="${project.build.finalName}.jar" out="${project.build.finalName}.jar"/> </input>${project.build.finalName}会当成字符串输入,而不会解析占位符。导致在打包的会报如下错 生效起因这个是官网原话,粗心就如果你应用了spring-boot-starter-parent,则maven-resources-plugin只认@ 为啥只认@,我贴下spring-boot-starter-parent pom的配置,大略大家就晓得怎么回事了 修复计划计划一:按官网的说法,将${project.build.finalName}改成@project.build.finalName@ <input> <jar in="@project.build.finalName@.jar" out="@project.build.finalName@.jar"/> </input>计划二:不间接引入spring-boot-starter-parent,而采纳dependencyManagement,占位符依然为${project.build.finalName} <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>计划三:批改maven-resources-plugin的configuration将useDefaultDelimiters设置true 示例: 计划四:在pom的 properties标签中,配置如下属性 <properties> <resource.delimiter>${}</resource.delimiter> </properties>总结springboot使maven-resources-plugin占位符生效问题的实质起因,就是springboot批改了原来maven-resources-plugin默认的占位符。springboot为啥这么干,他官网说了起因他的粗心是避免配置中的任何 Spring 占位符(例如 ${foo})被构建扩大。因而举荐还是用@ demo链接https://github.com/lyb-geek/springboot-learning/tree/master/springboot-proguard

February 8, 2022 · 1 min · jiezi

关于springboot:第七节SpringBoot高级属性配置二

SpringBoot的配置文件中,除了后面讲的根本配置形式。还能够配置List,Map,随机值等高级数据类型配置随机数com.rumenz.random=${random.value}com.rumenz.num=${random.int}com.rumenz.long.val=${random.long}com.rumenz.uuid=${random.uuid}com.rumenz.range=${random.int[100,1000]}测试案例package com.rumenz.lession7.controller;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;/** * @className: RumenzController * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/11/6 **/@Controller@RequestMapping("/rumenz")public class RumenzController { @Value("${com.rumenz.random}") private String random; @Value("${com.rumenz.num}") private Integer num; @Value("${com.rumenz.long.val}") private Long longVal; @Value("${com.rumenz.uuid}") private String uuid; @Value("${com.rumenz.range}") private Integer range; @RequestMapping("/index") @ResponseBody public String index(){ //配置文件中的随机值 String res=String.format("random %s num %d longVal %d uuid %s range %d",random,num,longVal,uuid,range); return res; }}浏览器拜访http://127.0.0.1:8080/rumenz/index返回random b92abe98c8eae52089dd78ae24fd47f5 num 354638503 longVal -7870587366296902654 uuid b3994be3-c183-4e2b-a375-55e27c28faef range 929List类型application.properties中配置com.rumenz.id[0]=1com.rumenz.id[1]=2com.rumenz.id[2]=3com.rumenz.uid=1,2,3,4测试案例package com.rumenz.lession7.controller;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import java.util.List;import java.util.Map;/** * @className: RumenzController * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/11/6 **/@Controller@RequestMapping("/rumenz")@ConfigurationProperties(prefix = "com.rumenz")public class RumenzController { //下标配置的数组值注入 private List<Integer> id; public List<Integer> getId() { return id; } public void setId(List<Integer> id) { this.id = id; } //逗号分隔 @Value("#{'${com.rumenz.uid}'.split(',')}") private List<Integer> uidList; @RequestMapping("/index1") @ResponseBody public String index1(){ //配置文件中的随机值 return getId().toString(); } @RequestMapping("/index2") @ResponseBody public String index2(){ //配置文件中的随机值 return uidList.toString(); }}拜访http://127.0.0.1:8080/rumenz/index1返回[1, 2, 3] ...

February 4, 2022 · 1 min · jiezi

关于springboot:SpringBoot-项目规范笔记2021

一年前整顿的 SpringBoot 我的项目标准怕丢了,毕竟过后用心写了,当初补传到博客上。 1. 利用划分标准利用零碎开发时,后端服务须要思考依照模块/微服务的划分准则来划分出多个SpringBoot模块,以便将来微服务化的重构。利用划分标准/准则如下: 横向拆分:依照不同的业务域进行拆分,例如订单、营销、风控、积分资源等。造成独立的业务畛域微服务集群。纵向拆分:把一个业务性能里的不同模块或者组件进行拆分。例如把公共组件拆分成独立的原子服务,下沉到底层,造成绝对独立的原子服务层。这样一纵一横,就能够实现业务的服务化拆分。要做好微服务的分层,须要梳理和抽取外围服务、公共利用,作为独立的服务下沉到外围和公共能力层,逐步造成稳固的服务中心,使前端利用能更疾速的响应多变的市场需求。服务拆分是越小越好吗?微服务的大与小是绝对的。比方在初期,咱们把交易拆分为一个微服务,然而随着业务量的增大,可能一个交易系统曾经缓缓变得很大,并且并发流量也不小,为了撑持更多的交易量,会把交易系统,拆分为订单服务、招标服务、转让服务等。因而服务的拆分力度需与具体业务相结合,总的准则是服务外部高内聚,服务之间低耦合。 2. 我的项目创立标准一个利用零碎中会依据状况,至多会创立一个SpringBoot我的项目及多个SpringBoot模块,创立工程时听从以下规定: GroupID 格局:com.{公司/BU }.业务线 [.子业务线]。 阐明:{公司/BU} 例如:alibaba/taobao/tmall/aliexpress 等 BU 一级;子业务线可选。 正例:com.taobao.jstorm 或 com.alibaba.dubbo.register ArtifactID 格局:产品线名-模块名。语义不反复不脱漏,先到地方仓库去查证一下。 正例:dubbo-client / fastjson-api / jstorm-toolVersion 格局 二方库版本号命名形式:主版本号.次版本号.订正号 1) 主版本号:产品方向扭转,或者大规模 API 不兼容,或者架构不兼容降级。 2) 次版本号:放弃绝对兼容性,减少次要性能个性,影响范畴极小的 API 不兼容批改。 3) 订正号:放弃齐全兼容性,修复 BUG、新增主要性能个性等。 阐明:留神起始版本号必须为:1.0.0,而不是 0.0.1。 2.1. 父模块创立标准一个利用零碎中会创立一个或多个SpringBoot我的项目,每个Spring Boot我的项目创立过程中(New -> Project),遵循如下标准: 名称标准我的项目类型Spring InitializrGroup遵循java包名标准,到公司层Artifact<我的项目/业务核心简称>-service 等TypeMaven ProjectLanguageJavaPackagingPOMJava Version放弃默认Name项目名称,与Artifact雷同Package<Group>.<我的项目/业务核心简称>Version可选取以后工夫较新的稳定版,例如release版本其中 Version 版本号命名形式: 主版本号.次版本号.订正号主版本号:产品方向扭转,或者大规模 API 不兼容,或者架构不兼容降级。次版本号:放弃绝对兼容性,减少次要性能个性,影响范畴极小的 API 不兼容批改。订正号:放弃齐全兼容性,修复 BUG、新增主要性能个性等。留神:起始版本号必须为:1.0.0,而不是 0.0.1。 3. POM标准3.1. 父模块POM标准父模块(tl-service)POM文件参考: <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.5</version> <relativePath/> </parent> <groupId>com.df.tl</groupId> <artifactId>tl-service</artifactId> <version>0.0.1-SNAPSHOT</version> <name>tl-service</name> <description>tl我的项目的父模块</description> <!-- 属性--> <properties> <java.version>1.8</java.version> <spring-parent.version>2.4.5</spring-parent.version> <lombok.version>1.18.0</lombok.version> <mybatis.version>1.3.2</mybatis.version> <mysql.version>8.0.16</mysql.version> <druid.version>1.1.13</druid.version> </properties> <!-- 子模块,申明--> <modules> <module>tl-api</module> <module>tl-project-service</module> <module>tl-task-service</module> </modules> <!-- 打包形式 pom--> <packaging>pom</packaging> <!-- dependencyManagement 治理--> <dependencyManagement> <dependencies> <!-- spring web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${spring-parent.version}</version> </dependency> <!-- spring test--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <version>${spring-parent.version}</version> </dependency> <!-- lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <!-- mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.version}</version> </dependency> <!-- mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!-- druid 数据源--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${druid.version}</version> </dependency> </dependencies> </dependencyManagement> <build> <!-- pluginManagement 治理--> <pluginManagement> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </pluginManagement> </build></project>须要留神的中央如下: ...

February 3, 2022 · 3 min · jiezi

关于springboot:Springboot-注解-Cacheable自定义单个key设置expire超时时间-并在配置文件里配置

Springboot RedisCacheManager 类的配置 指定key的过期工夫 并在配置文件里配置 目标&成果在springBoot中配置了RedisCache,当应用@Cacheable注解时,默认为redisCache,通过在配置文件里设置不同key的过期工夫,达到可自定义key过期工夫的成果。 计划 step 1新建一个Map类,用于寄存要设置的key @ConfigurationPropertiespublic class Properties { private final Map<String, Duration> initCaches = Maps.newHashMap(); public Map<String, Duration> getInitCaches() { return initCaches; }}step2在redis配置类里编写cacheManager,并将map set进去 @Autowiredprivate Properties properties; @Beanpublic CacheManager cacheManager(RedisConnectionFactory connectionFactory) { RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(10)).disableCachingNullValues(); RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory); ImmutableSet.Builder<String> cacheNames = ImmutableSet.builder(); ImmutableMap.Builder<String, RedisCacheConfiguration> cacheConfig = ImmutableMap.builder(); for (Map.Entry<String, Duration> entry : properties.getInitCaches().entrySet()) { cacheNames.add(entry.getKey()); cacheConfig.put(entry.getKey(), defaultCacheConfig.entryTtl(entry.getValue())); } return RedisCacheManager.builder(redisCacheWriter) .cacheDefaults(defaultCacheConfig) .initialCacheNames(cacheNames.build()) .withInitialCacheConfigurations(cacheConfig.build()) .build();} step3在Springboot yml文件里配置相干的key的过期工夫 就能够指定@Cacheable的value的过期工夫 ...

January 31, 2022 · 1 min · jiezi

关于springboot:正则表达式过滤掉数字广告

public static String replaceSpecialNumeric(String numeric) { //广告数字的正则 String regex = "[A-Za-z0-9⓪①②③④⑤⑥⑦⑧⑨⑩零壹贰叁肆伍陆柒捌玖拾⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉]{5,}"; if (StringUtils.isNotBlank(numeric)) { Pattern p = Pattern.compile(regex); Matcher matcher = p.matcher(numeric); return matcher.replaceAll("*"); }else { return wechat; }}成果: public static void main(String[] arg) { String b = replaceSpecialNumeric("ⅥⅦ111 叁1sss aaa 草泥马"); System.out.println(b); }控制台打印: aaa 草泥马

January 31, 2022 · 1 min · jiezi

关于springboot:第五节SpringBoot常用注解介绍

[TOC] 启动类上的注解@SpringBootApplication这个注解会在SpringBoot启动类上。这个注解实际上蕴含3个注解@SpringBootConfiguration,@EnableAutoConfiguration和@ComponentScan@SpringBootConfiguration继承@Configuration两个注解的性能一样。也就是标注以后类是配置类。会将以后类中申明的一个或者多个@Bean注解标记的办法的实例注入到Spring容器中。实例名就是对象名。@EnableAutoConfiguration是SpringBoot的主动配置注解。能够将符合条件的@Configuration加载到SpringBoot,并生成对应配置类的Bean,加载到Srping容器。@ComponentScan扫描以后包和子包下被@Component,@Controller,@Service,@Respository注解的类并注入到Spring容器。前端控制器@Controller@Controller注解在类上,示意这是一个管制层bean。@RestController@RestController注解在类上,示意这是一个管制层bean,相当于@ResponseBody和·@Controller的组合注解。应用此注解无奈返回jsp,html页面,InternalResourceViewResolver不起作用。返回的内容就是return的内容。@RequestMapping@RequestMapping用来解决申请地址映射的注解。能够申明在类或者办法上。用在类上示意所有的申请的父门路。 @RequestMapping注解有6个属性 value,methodvalue 申请的办法method 申请的类型,GET,POST,PUT,DELETEconsumes,producesconsumes 指定能够解决申请数据的类型。如:application/json和text/htmlproduces 指定返回数据的类型。只有当request申请头Accept字段中蕴含此类型,才返回数据params,headersparams 指定request中蕴含某些参数值,才解决。headers 指定request申请头蕴含header值,才解决。@RequestBody和@ResponseBody@RequestBody会将request申请头中的body转换成string字符串类型。这个注解会呈现在申请办法的参数上@ResponseBody会将Map对象转化成json格局输入到HTTP中,这个注解会呈现在申请的办法上。@PathVariable,@RequestParam,@ModelAttribute,@RequestAttribute@PathVariable@RequestMapping(value = "/index7/{id}",method = RequestMethod.GET)从申请的URI中提取id。@RequestParam从申请头中获取参数@RequestAttribute ,@ModelAttribute@RequestAttribute注解取的参数是我的项目中解析进去的。不是从前端传过来的。能够通过ModeAttribute或HandlerInterceptor中预存。 @ModelAttribute 用在办法参数注解上,能够接管前端参数,然而要求数据格式是x-www-form-urlencoded用在办法上能够预存属性值。@GetMappingGetMapping注解曾经默认封装了@RequestMapping(method = RequestMethod.GET)@PostMappingPostMapping注解曾经默认封装了@RequestMapping(method = RequestMethod.POST)@GetMapping和@PostMapping要配合@RestController应用,否则会报404。服务层@Service注解在类上,标注这是一个服务层长久层@Repository 注解于类上,示意于长久层配置@Component它是一个通用注解,,不属于@Controller和@Service的组件,咱们就能够用@Componment。它能够标注这个类被Spring容器治理。@Configuration@Configuration标注在类上,配置spring容器(利用上下文)。相当于把该类作为spring的xml配置文件中的<beans>。@Configuration注解的类中,应用@Bean注解标注的办法,返回的类型都会间接注册为bean。@Configuration注解基于@Component,所以他们的性能是一样的,然而意义有所不同。@Bean该注解在该类的办法上,AnnotationConfigApplicationContext将配置类中标注了@Bean的办法的返回值辨认为Spring Bean,并注册到容器中,纳入IoC容器治理。依赖注入@Autowired默认是依照类型注入的(属于Sping的注解),默认状况下要求被依赖的对象必须存在,如果要容许null值,能够设置它的required属性为false(@Autowired(required=false) )@Resource默认依据名称进行依赖注入(属于J2EE的注解),默认状况下依据名称注入,名称能够通过name属性进行指定,如果没有指定name属性,默认取字段名进行装置名称查找.@Qualifier这个是Spring中的一个注解,如果有多个类型雷同的Bean,就能够应用@Qualifier根据名字辨别注入。@Value通过@Value将配置文件中定义的值注入到Bean中本小结源码地址:GitHub:https://github.com/mifunc/spr...Gitee:https://gitee.com/rumenz/spri...https://rumenz.com/rumenbiji/...介绍我的博客 https://rumenz.com/我的工具箱 https://tooltt.com/微信公众号:【入门小站】 关注【入门小站】回复【1001】获取 linux常用命令速查手册关注【入门小站】回复【1003】获取 LeetCode题解【java语言实现】关注【入门小站】回复【1004】获取 Java根底外围总结关注【入门小站】回复【1009】获取 阿里巴巴Java开发手册

January 27, 2022 · 1 min · jiezi

关于springboot:AutoConfigureAfter和AutoConfigureBefore排序失效了

@AutoConfigureAfter和@AutoConfigureBefore排序生效了?注释聊聊SpringBoot Bean加载和 主动配置的程序问题。 理论误区来看看理论开发中存在的问题。咱们想要的后果A-->B-->C,上面写法是最常见的谬误。 @Configurationpublic class ConfigurationA { ConfigurationA(){ System.out.println("CofigurationA 曾经被初始化!"); }}@Configuration@AutoConfigureAfter(ConfigurationA.class)public class ConfigurationB { ConfigurationB(){ System.out.println("ConfigurationB 曾经被初始化!"); }}@Configuration@AutoConfigureAfter(ConfigurationB.class)public class ConfigurationC { ConfigurationC(){ System.out.println("CofigurationC 曾经被初始化!"); }}来来来执行一把。。。。 执行后果:CofigurationA 曾经被初始化!ConfigurationB 曾经被初始化!CofigurationC 曾经被初始化!WTF!!!!!!!!不是说有问题吗?别急!!调整下代码,想要的后果是C-->B-->A,来将代码调整下: @Configuration@AutoConfigureAfter(ConfigurationB.class)public class ConfigurationA { ConfigurationA(){ System.out.println("CofigurationA 曾经被初始化!"); }}@Configuration@AutoConfigureAfter(ConfigurationC.class)public class ConfigurationB { ConfigurationB(){ System.out.println("ConfigurationB 曾经被初始化!"); }}@Configurationpublic class ConfigurationC { ConfigurationC(){ System.out.println("CofigurationC 曾经被初始化!"); }}来来开席开席!!!! 执行后果:CofigurationA 曾经被初始化!ConfigurationB 曾经被初始化!CofigurationC 曾经被初始化!从下面的后果是能够看出@AutoConfigureAfter并没有什么卵用。第一次可能失去正确后果是老天保佑。。。。。 所以来看看源码:@AutoConfigureAfter归纳来说得益于SpringBoot主动配置(@EnableAutoConfiguration);@EnableAutoConfiguration通过@Import将EnableAutoConfigurationImportSelector引入,这边次要看下EnableAutoConfigurationImportSelector-->selectImports()办法 public String[] selectImports(AnnotationMetadata metadata) { if (!isEnabled(metadata)) { return NO_IMPORTS; } try { AnnotationAttributes attributes = getAttributes(metadata); //加载META-INF下spring.factories配置类 List<String> configurations = getCandidateConfigurations(metadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(metadata, attributes); configurations.removeAll(exclusions); //将配置类进行排序 configurations = sort(configurations); recordWithConditionEvaluationReport(configurations, exclusions); return configurations.toArray(new String[configurations.size()]); } catch (IOException ex) { throw new IllegalStateException(ex); } } protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }看到这里法外狂徒 "张三"默默的在META-INF下spring.factories加上了....... ...

January 26, 2022 · 1 min · jiezi

关于springboot:SpringBoot工程下Lombok热部署实现健康检查全局异常处理响应标准

lombok应用步骤:1.装置lombok插件2.增加lombok依赖3.在对应的类上应用lombok提供的注解 lombok提供的注解:@Data此注解形容类时,在编译时会为此类生成get,set,toString,hashCode,equals等办法@ToString提供重写的toString办法@Setter提供set办法@Getter提供get办法@Slf4j:lombok发现类上有此注解时,会为此类创立一个日志对象,其变量为log@AllArgsConstructor提供全参构造函数@NoArgsConstructor提供无参构造函数 lombok原理:在java源码编译时,基于lombok做了拦挡,底层借助字节码技术为class文件做了加强 热部署实现增加依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency>依赖下载当前,可重启reload我的项目,而后当咱们批改了src/main/java目录下的java文件或批改了src/main/resources目录下的配置文件时,默认都会重启你的web服务器,然而批改了测试类或html文件不会主动重启和部署。 健康检查实现增加依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>启动我的项目,在浏览器中输出如下地址:(SpringBoot默认关上的监控选项无限)http://localhost/actuator 如果心愿查看更多actuator选项,能够在spring boot中配置文件application.properties中增加如下语句: management.endpoints.web.exposure.include=*而后,重启服务器,基于拜访http://localhost/actuator地址... 全局异样解决解决标准:捕捉异样时与抛出的异样必须齐全匹配,或者捕捉异样是抛出异样的父类类型。防止间接抛出RuntimeException,更不容许抛出Exception或者Throwable,应应用有业务含意的自定义异样(例如ServiceException)。捕捉异样后必须进行解决(例如记录日志)。如果不想解决它,须要将异样抛给它的调用者。最外层的逻辑必须解决异样,将其转化成用户能够了解的内容。避免出现反复的代码(Don’t Repeat Yourself),即DAY准则。 异样解决形式:1.try{}catch(){} 毛病代码量大,可重复性差,难以保护 2.在Controller类中定义一个或多个异样解决办法所有的异样解决办法须要用@ExceptionHandler进行形容,并申明它形容的办法能够解决的异样类型。毛病是只能解决以后Controller类中各个办法呈现的RuntimeException异样或者是其子类类型的异样。 3.在管制逻辑层定义全局异样解决类以及异样解决办法 package com.cy.pj.goods.controller;import lombok.extern.slf4j.Slf4j;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;@Slf4j@ControllerAdvice//此注解形容的类为全局异样解决类,在此类中能够定义多个异样解决办法public class GlobalExceptionHandler { @ExceptionHandler(RuntimeException.class) @ResponseBody public JsonResult doHandleRuntimeException(RuntimeException e) { log.error("RuntimeException.exception{}",e.getMessage()); return new JsonResult(e.getMessage()); } @ExceptionHandler(IllegalArgumentException.class) @ResponseBody public JsonResult doHandleException(IllegalArgumentException e) { log.error("IllegalArgumentException.exception{}",e.getMessage()); return new JsonResult(e.getMessage()); }}如果Controller类中有异样解决办法,那么必定还是遵循部分优先的准则,由Controller类中的异样解决办法来解决异样。 如果全局异样解决类中存在多个异样解决办法,而其中一个办法的可解决异样的类型是另一个办法的子类类型,那么当出现异常时,则会由这个子类类型的办法来解决 响应规范设计

January 25, 2022 · 1 min · jiezi

关于springboot:带你从0搭建一个Springbootelasticsearchcanal的完整项目-dailyhub

首发公众号:MarkerHub 作者:吕一明 原文链接:https://www.zhuawaba.com/post... 线上演示地址:https://www.zhuawaba.com/dail... 视频解说:https://www.bilibili.com/vide... 源码地址:请关注公众号:Java问答社,回复【678】获取 1、前言咱们常常浏览很多网页,看到一些感觉有用、或者有意思的网页时候,咱们通常会珍藏到书签。然而当书签的珍藏越来越多,分类越来越多,想找到之前的那条珍藏就比拟麻烦,尽管也有搜寻性能,但还须要另外点击很多操作。 最重要的是,珍藏网页的时候我往往须要记录一些浏览心得,作为我浏览的脚印和记忆。其实对我来说,珍藏的分类不是特地重要,这是一个费脑的过程,因为很多网页能够放到多个文件夹,这时候又呈现了抉择艰难症了,网页各式各样,总不能给每种网页都起个分类珍藏。对我来说有点冗余。 于是我打算开发一个零碎,以工夫为记录线,在未关上网站的时候就能够疾速记录我以后浏览网页的网址和题目,而后我还能够记录心得。另外还须要一个很弱小的搜索引擎,疾速搜寻记录。这样我能够查看我每天浏览了那些网页,而后还能够分享到珍藏广场上给更多的网友。 那么,接下来,跟着我,一起去实现这个我的项目的开发吧 我的项目性能公众号扫码登录注册疾速珍藏网页收藏夹列表珍藏检索技术栈后端:springboot、spring data jpa、mysql、redis、elasticsearch、canal、mapstruct 前端:bootstrap 5 其实之前我在eblog我的项目中做个搜寻性能,那时候应用的是rabbitmq同步数据到es,这次我为了缩小代码开发的量,应用了canal基于binlog同步数据到es,这波及到服务搭建的过程,后续我都会一一解说。 2、线上演示https://www.zhuawaba.com/dailyhub 3、新建springboot我的项目,整合jpa、freemarker关上IDEA开发工具,咱们先来新建一个springboot我的项目,很惯例的操作,项目名称dailyhub,咱们把须要的jar间接引入,比方jpa、redis、mysql、lombok、dev调试。 新建我的项目 maven导入相干的jar,本来我是想做一个前后端拆散我的项目的,起初想想话太多工夫在前端,我又不太想了,于是我应用了freemarker作为模板引擎。 我的项目初建 对了,因为常常用到一些工具类,我喜爱用hutool,所以记得提前引入哈: pom.xml<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.16</version></dependency>接下来,咱们整合jpa和freemarker,让我的项目能够拜访数据库和展现页面内容。 整合jpajpa的整合及其简略,咱们只须要配置数据源的信息,连贯上数据库,其余的整合工作都曾经帮咱们配置好的了。 application.ymlspring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost/dailyhub?useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8 username: root password: admin jpa: database: mysql show-sql: true hibernate: ddl-auto: update 下面配置中,记得要去新建一个dailyhub的数据库哇,因为后续的用户名称可能会有头像等特殊字符,所以新建数据库字符集记得要用utf8mb4的格局哈。 而后因为是jpa,表和字段信息在我的项目启动时候会随着你定义的bean类属性信息主动创立。所以咱们不须要手动去建表。 为了测试,咱们先来定义用户表信息,我打算通过用户扫描二维码形式实现登录,所以记录的信息不多,我也不须要收集太多用户信息,所以字段非常简单。 com.markerhub.entity.User @Data@Entity@Table(name = "m_user")public class User implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; // 头像 private String avatar; // 微信用户身份id @JsonIgnore private String openId; // 上次登录 private LocalDateTime lasted; private LocalDateTime created; private Integer statu;}而后接下来新建UserRepository,当然了,因为咱们是我的项目实战,所以要求你须要有点jpa的常识哈。UserRepository继承JpaRepository,JpaRepository是SpringBoot Data JPA提供的十分弱小的根底接口,领有了根本CRUD性能以及分页性能。 ...

January 25, 2022 · 13 min · jiezi

关于springboot:124周末汇报

angular首页问题查问参数不起作用,这个问题是学长解决的,但感觉有必要记录一下查问时机器人治理连贯状态不起作用 在mockApi中打印承受到的参数,查看控制台,发现传过来的连贯状态参数为空 查问时的过程点击查问后执行onSubmit()办法 onSubmit(queryForm: FormGroup): void { this.reload({...this.params, ...queryForm.value}); }onSubmit()执行reload()办法 /** * 查问 * @param params page: 当前页 size: 每页大小 */ reload(params: Params): void { // 将参数转换为路由参数 const queryParams = CommonService.convertToRouteParams(params); console.log('queryParams',queryParams); this.router.navigate(['./'], { relativeTo: this.route, queryParams: queryParams, }).then(); } /** * 将参数转换为路由参数 * @param params 参数 * @return 实用于route的Params */ public static convertToRouteParams(params: { [header: string]: string | string[] | number | number[] | null | undefined; }) : { [header: string]: string | string[]; } { const queryParams = {} as { [header: string]: string | string[]; }; // 过滤掉undefined及null的数据 for (const key in params) { if (params[key] !== undefined) { const value = params[key]; if (value !== undefined || value !== null) { if (typeof value === 'string') { if (value.length > 0) { queryParams[key] = value; } } else if (typeof value === 'number') { queryParams[key] = value.toString(); } else if (Array.isArray(value)) { queryParams[key] = []; (value as []).forEach(v => { if (typeof v === 'number') { (queryParams[key] as string[]).push((v as number).toString()); } else { (queryParams[key] as string[]).push(v); } }); } } } } return queryParams; }在这个办法中并没有对boolean值得解决,所以传过来的boolean值间接被过滤掉了,而我在抉择组件中恰好将类型申明为了boolean,这就导致了这样的问题。批改后解决 ...

January 24, 2022 · 2 min · jiezi

关于springboot:第四节SpringBoot中web模版数据渲染展示

在第一节咱们演示通过接口返回数据,数据没有渲染展现在页面上 。在这里咱们演示一下从后盾返回数据渲染到前端页面的我的项目案例.模板引擎SpringBoot是通过模版引擎进行页面后果渲染的,官网提供预设配置的模版引擎次要有ThymeleafFreeMarkerVelocityGroovyMustache咱们在这里演示应用Thymeleaf和FreeMarker模板引擎。ThymeleafThymeleaf是实用于 Web 和独立环境的古代服务器端 Java 模板引擎。 Thymeleaf 的次要指标是为你的开发工作流程带来优雅的天然模板——HTML能够在浏览器中正确显示,也能够作为动态原型工作,从而增强开发团队的合作。 凭借 Spring Framework 的模块、与你最喜爱的工具的大量集成以及插入你本人的性能的能力,Thymeleaf 是古代 HTML5 JVM Web 开发的现实抉择——只管它还有更多功能。 新建一个模块 抉择咱们须要的组建Developer Tools中的Spring Boot DevToolsWeb中的Spring WebTemplate Engines 中的Thymeleaf 也能够间接在pom.xml中引入thymeleaf依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>创立com.rumenz.lession4.controller包 创立模板页面src/main/resources/templates/index.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>thymeleaf - 入门小站</title></head><body><p th:text="'名字:'+${name}"></p><p th:text="'网址:'+${url}"></p></body></html>创立controllercom.rumenz.lession4.controller.ThymeleafRumenControllerpackage com.rumenz.lession4.controller;import org.springframework.stereotype.Controller;import org.springframework.ui.ModelMap;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;/** * @className: ThymeleafRumenController * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/11/1 **/@Controller@RequestMapping("/")public class ThymeleafRumenController { @RequestMapping(value = "/index",method= RequestMethod.GET) public String index(ModelMap m){ //数据也能够从数据库查问进去返回 m.addAttribute("name", "入门小站"); m.addAttribute("url", "https://rumenz.com"); //返回是一个页码:src/main/resources/templates/thymeleaf.html return "thymeleaf"; }}启动我的项目 ...

January 24, 2022 · 1 min · jiezi

关于springboot:SpringBoot2022草稿

SpringBoot2022spring 向spring切换 不对旧的组件进行代码批改1、配置类 @EnableConfigurationProperties 的作用 将SsoProperties 退出到容器中开启SsoProperties的配置绑定性能@Configuration@EnableConfigurationProperties(value = SsoProperties.class)public SsoFilterConfiguration{ // 形参,spring会去容器中找SsoProperties这个bean @Bean public SsoFilter ssoFilter(SsoProperties ssoProperties) { SsoFilter ssoFilter = new SsoFilter(); ssoFilter.setName(ssoProperties.getName()); ssoFilter.setPassword(ssoProperties.getPassword()); return ssoFilter; }}2、properties类 @ConfigurationProperties的作用 指定主配置文件中clair.sso前缀的值绑定到对应的属性上@ConfigurationProperties(prefix = "clair.sso")public SsoProperties{ private String name; private String password; // 提供getter setter办法 不必lombok}3、主性能类 public SsoFilter{ private String name; private String password; // getter setter}对旧的组件进行代码批改@Component@ConfigurationProperties(prefix = "clair.sso")public SsoFilter{ private String name; private String password; // getter setter}留神,两种形式不能共存 主动配置原理springboot 装载所有的主动配置类依据条件,判断主动配置类是否失效。每个配置类都会绑定一个xxxProperties。咱们能够再配置文件中指定xxxProperties的值,从而实现对组件属性的自定义配置失效的主动配置类,再依据各种条件判断是否往容器中增加各种组件只有用户本人配置了,就以用户的优先(通过 @ConditionalOnMissingBean实现)定制化配置 ...

January 24, 2022 · 1 min · jiezi

关于springboot:第三节SpringBoot中web项目推荐目录结构

SpingBoot 365打算开始更新了,打算手敲365个SpringBoot案例回顾总结造成常识体系。目前曾经输入了32节的内容。所有源码托管在GitHub和Gitee上。上面是我创立的目录构造.├── ./pom.xml└── ./src ├── ./src/main │   ├── ./src/main/java │   │   └── ./src/main/java/com │   │   └── ./src/main/java/com/rumenz │   │   ├── ./src/main/java/com/rumenz/Lession3Application.java │   │   ├── ./src/main/java/com/rumenz/config │   │   ├── ./src/main/java/com/rumenz/controller │   │   ├── ./src/main/java/com/rumenz/domain │   │   ├── ./src/main/java/com/rumenz/dto │   │   ├── ./src/main/java/com/rumenz/entity │   │   ├── ./src/main/java/com/rumenz/mapper │   │   ├── ./src/main/java/com/rumenz/repository │   │   ├── ./src/main/java/com/rumenz/service │   │   │   ├── ./src/main/java/com/rumenz/service/1.txt │   │   │   └── ./src/main/java/com/rumenz/service/impl │   │   ├── ./src/main/java/com/rumenz/utils │   │   └── ./src/main/java/com/rumenz/vo │   └── ./src/main/resources │   ├── ./src/main/resources/application.properties │   ├── ./src/main/resources/mapper │   ├── ./src/main/resources/static │   └── ./src/main/resources/templates └── ./src/test └── ./src/test/java └── ./src/test/java/com └── ./src/test/java/com/rumenz └── ./src/test/java/com/rumenz/Lession3ApplicationTests.java我的项目构造启动类Lession3Application.java个别放在com.rumenz下前端控制器controller前端控制器又叫controller层,放在./src/main/java/com/rumenz/controller门路下,也就是com.rumenz.controller包下。服务接口层 service也叫service层,放在./src/main/java/com/rumenz/service门路下,也就是com.rumenz.service包下。服务接口实现层 impl服务接口层的具体实现类,放在./src/main/java/com/rumenz/service/impl门路下,也就是com.rumenz.service.impl包下。数据拜访层 repository或mapper拜访数据的库的接口jpa我的项目:放在./src/main/java/com/rumenz/repository门路下。也就是com.rumenz.repository包下。mybatis我的项目:放在./src/main/java/com/rumenz/mapper门路下。也就是com.rumenz.mapper包下。工具类库 utils放一些专用的小工具办法。放在./src/main/java/com/rumenz/utils门路下。也就是com.rumenz.utils包下。配置类 config我的项目的所有配置类。放在./src/main/java/com/rumenz/config门路下。也就是com.rumenz.config包下。数据传输对象 DTODTO(Data Transfer Object)示意一个数据传输对象,DTO通常用于前端管制层controller和服务层service之间传输对象,DTO个别不会间接返回给前端, 由服务层返回。前端界面显示的字段会新封装成一个VO(View Object)前端视图对象VOVO(View Object)用来封装前端界面显示字段。放在./src/main/java/com/rumenz/vo门路下。也就是com.rumenz.vo包下。动态资源的目录构造配置文件./src/main/resources/application.properties动态资源目录./src/main/resources/static用来寄存css,js,image等动态资源。模板目录./src/main/resources/templates用来寄存html模板。mybatis映射文件./src/main/resources/mapper用来存在xml的sql文件。残缺我的项目构造 ...

January 20, 2022 · 1 min · jiezi

关于springboot:聊聊springboot项目全局异常处理那些事儿

前言之前咱们业务团队在解决全局异样时,在每个业务微服务中都退出了@RestControllerAdvice+@ExceptionHandler来进行全局异样捕捉。某次领导在走查代码的时候,就提出了一个问题,为什么要每个微服务项目都要本人在写一套全局异样代码,为什么不把全局异样块抽成一个公共的jar,而后每个微服务以jar的模式引入。前面业务团队就依据领导的要求,把全局异样块独自抽离进去封装成jar。明天聊的话题就是对于把全局异样抽离进去,产生的一些问题 问题一:全局异样抽离进去后,业务错误码如何定义?之前团队的业务错误码定义是:业务服务前缀 + 业务模块 + 错误码,如果是辨认不了的异样,则应用业务前缀 + 固定模块码 + 固定错误码。之前的全局异样伪代码如下 @RestControllerAdvice@Slf4jpublic class GlobalExceptionBaseHandler { @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public AjaxResult handleException(Exception e) { String servicePrifix = "U"; String moudleCode = "001"; String code = "0001"; String errorCode = servicePrifix + moudleCode + code; String msg = e.getMessage(); if(StringUtils.isEmpty(msg)){ msg = "服务端异样"; } log.error(msg, e); return AjaxResult.error(msg, errorCode); } }当初全局异样抽离进去后,那个业务服务前缀如何辨认?之前未抽离时,业务服务前缀各个业务服务间接写死在代码里。过后咱们长期的解决方案是通过spring.application.name来解决。因为全局异样代码块抽离进去后,最终还是要被服务引入的。因而获取业务服务前缀的伪代码能够通过如下获取 public enum ServicePrefixEnum { USER_SERVICE("U","用户核心"); private final String servicePrefix; private final String serviceDesc; ServicePrefixEnum(String servicePrefix,String serviceDesc) { this.servicePrefix = servicePrefix; this.serviceDesc = serviceDesc; } public String getServicePrefix() { return servicePrefix; } public String getServiceDesc() { return serviceDesc; }} public String getServicePrefix(@Value("${spring.application.name}") String serviceName){ return ServicePrefixEnum.valueOf(serviceName).getServicePrefix(); }但这种计划其实是存在弊病 ...

January 18, 2022 · 2 min · jiezi

关于springboot:SpringBoot在Tomcat部署war包

启动类配置继承SpringBootServletInitializer @SpringBootApplicationpublic class TestApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(TestApplication.class); }}打包形式配置 <packaging>war</packaging>移除内置Tomcat <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency>WebSocket谬误 <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency>Bean按需加载@Configurationpublic class WebSocketConfig { @Bean @ConditionalOnProperty(name = "system.package", havingValue = "jar", matchIfMissing = true) public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }}Tomcat设置Host节点减少Context能够间接通过ip+端口形式拜访,须要将appBase革除,避免启动两次利用 <Host name="localhost" appBase="" unpackWARs="true" autoDeploy="true"> <Context path="" docBase="webapps/test" reloadable="false"/> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" /></Host>注意事项对于框架封装援用jar包,须要留神工程项目中只能有一个类继承自SpringBootServletInitializer,否则会导致ApplicationContext初始化两次

January 16, 2022 · 1 min · jiezi

关于springboot:第一节创建SpringBoot项目并运行HelloWorld

SpingBoot 365打算开始更新了,打算手敲365个SpringBoot案例回顾总结造成常识体系。目前曾经输入了32节的内容。所有源码托管在GitHub和Gitee上。1.第一节:创立SpringBoot我的项目并运行HelloWorld.md2.第二节:SpingBoot单元测试.md3.第三节:SpringBoot中web我的项目举荐目录构造.md4.第四节:SpringBoot中web模版数据渲染展现.md5.第五节:SpringBoot罕用注解介绍.md6.第六节:SpingBoot根本配置一.md7.第七节:SpringBoot高级属性配置二.md8.第八节:SpringBoot指定配置文件配置三.md9.第九节:SpringBoot在线文档Swagger2入门.md10.第十节:SpringBoot中的日志治理.md11.第十一节:Springboot整合log4j2日志.md12.第十二节:Springboot多环境配置.md13.第十三节:应用Lombok简化你的代码.md14.第十四节:SpringBoot应用JdbcTemplate拜访操作数据库根本用法.md15.第十五节:SpringBoot应用JPA拜访数据库.md16.第十六节:SpringBoot应用JPA一对多,多对多拜访数据库.md17.第十七节:SpringBoot应用JPA实现用户角色多对多查问.md18.第十八节:SpringBoot集成MyBatis注解形式拜访数据库.md19.第十九节:SpringBoot集成MyBatis(XML)形式拜访数据库.md20.第二十节:SpringBoot集成MyBatis实现分页.md21.第二十一节:SpringBoot应用Mybatis22.第二十二节:SpringBoot集成MyBatis-Plus实现增删改查.md23.第二十三节:SpringBoot对立异样解决3种形式.md24.第二十四节:SpringBoot中数据校验JSR303.md25.第二十五节:SpringBoot中自定义一个JSR303标准的注解校验器.md26.第二十六节:SpringBoot集成Redis配置的基本操作.md27.第二十七节:SpringBoot中的stream实现音讯队列.md28.第二十八节:SpringBoot中应用Redis实现超时勾销订单.md29.第二十九节:SpringBoot中Redis实现音讯订阅.md30.第三十节:SpringBoot集成ehcache应用JVM内存模式缓存.md31.第三十一节:SpringBoot集成ehcache应用Redis模式缓存.md32.第三十二节:SpringBoot集成WebSocket.md未完待续。。。。。什么是SpringBootSpring Boot是Pivotal于 2014年开发的开源 Java 框架,简化了部署 Java 企业 Web 应用程序的工作。它是一个构建在 Spring 框架之上的我的项目,它简化了Java开发。SpringBoot和Spring的关系 SpringBoot的长处疾速轻松地开发基于 Spring 的应用程序;无需部署war文件;帮忙将 Tomcat、Jetty 或 Undertow 间接嵌入到应用程序中;无需 XML 配置下面简略介绍了SpringBoot,上面咱们就开始创立并运行一个SpringBoot我的项目开发环境JDK1.8Maven 3.6.1SpringBoot 2.5.6先创立一个父工程创立一个父工程蕴含每一大节的我的项目案例,也就是说每一大节的我的项目都是一个模块。关上idea点击Create New Project ,创立一个新我的项目 抉择Maven我的项目,左边不要勾选(不抉择模板) 抉择我的项目创立的地位 删除src目录 创立一个SpringBoot我的项目右边抉择我的项目目录右键New一个Module 抉择Spring Initializr创立SpringBoot我的项目 输出Maven坐标和抉择Java版本 抉择Developer Tools 中的Spring Boot DevToolsSpring Boot DevTools模块可能实现热部署,增加类.增加办法,批改配置文件,批改页面等,都能实现热部署. 抉择Web中的Spring Web咱们演示的是Java Web我的项目,所以要抉择Spring Web 这样咱们的我的项目就创立好了创立入门的Hello World程序创立lession1.controller包。 创立HelloWorldController.java文件创立com.rumenz.helloworld.controller.HelloWorldController.java package com.rumenz.lession1.controller;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;/** * @className: HelloWorldController * @description: TODO 类形容 * @author: 入门小站 rumenz.com * @date: 2021/10/31 **/@RestControllerpublic class HelloWorldController { @GetMapping("/") public String index(){ return "Hello World 入门小站"; }}@RestController注解是一种快捷方式,它所申明的控制器在返回响应时,就如同应用了@ResponseBody 注解一样。它会通知Spring 将返回类型序列化为适合的格局,默认状况下为JSON 格局。通过用@RestController正文控制器类,你不再须要向所有申请映射办法增加@ResponseBody@GetMapping是一个组合正文,相当于@RequestMapping(method = RequestMethod.GET).启动我的项目Lession1Application是我的项目启动类,是默认生成的,默认端口是8080, 选中右键-> Run As –> Java Application ...

January 15, 2022 · 1 min · jiezi

关于springboot:springboot管理系统基于员工角色和文件权限的分级的后台管理系统源码

 springboot管理系统是一种实现JPA存储库的办法,能够轻松地在应用程序中增加数据拜访层。CRUD代表创立、检索、更新、删除,这些都是能够在数据库中执行的操作。在本文中,咱们将看到一个示例,阐明如何应用spring数据JPA构建基于员工角色和文件权限的分级的后盾管理系统。 源码:s.ymzan.top 数据库是互相关联的数据的汇合,它有助于高效地从数据库中检索、插入和删除数据,并以表、视图、模式、报告等模式组织数据。因而,对于任何应用程序,数据库都是最重要的模块之一,须要有一种与之通信的形式。因而,为了应用Spring构架欠缺的后盾权限管理系统,须要遵循以下步骤: 一、去spring initializr 并创立一个新的我的项目,其依赖关系如下: ●Spring Web ●Spring Data JPA ●MySQL Driver 二、下载starter我的项目并将其导入IDE中。 三、在我的项目同步之后,咱们将创立一个模型类公司与正文@ entity这意味着这个类映射到数据库中的表。增加数据类型与数据库中列雷同的数据成员,并生成构造函数和getter。增加正文@ id指向数据成员,该成员将在表和中充当主键属性@Generatedvalue(策略= generationtype.auto)以便主动减少主键属性。上面是这个类的实现: @Entity public class Company { // Primary ID which increments // automatically when new entry // is added into the database @Id @GeneratedValue(strategy = GenerationType.AUTO) int id; String name; // In months int duration; String profile; // Can be 0 int stipend; boolean workFromHome; public Company() { } // Parameterized constructor public Company(String name, int duration, String profile, int stipend, boolean workFromHome) { this.name = name; this.duration = duration; this.profile = profile; this.stipend = stipend; this.workFromHome = workFromHome; } // Getters and setters of // the variables public int getId() { return id; } public String getName() { return name; } public int getDuration() { return duration; } public String getProfile() { return profile; } public int getStipend() { return stipend; } public void setId(int id) { this.id = id; } public boolean isWorkFromHome() { return workFromHome; } 四、当初,创立一个接口 CompanyRepository与正文@这将实现CrudRepository. 执行CRUD操作的函数将在接口中定义,如下所示: @Repository public interface CompanyRepository extends CrudRepository<Company, Integer> { Company findById(int id); List<Company> findAll(); void deleteById(int id); } 留神:这些函数不会被实现,因为它们曾经在CrudRepository中实现了。 五、当初,咱们将创立如下所示的REST api (GET, POST, PUT, DELETE): @RestController public class CompanyController { @Autowired private CompanyRepository repo; // Home Page @GetMapping("/") public String welcome() { return "<html><body>" + "<h1>WELCOME</h1>" + "</body></html>"; } // Get All Notes @GetMapping("/company") public List<Company> getAllNotes() { return repo.findAll(); } // Get the company details by // ID @GetMapping("/company/{id}") public Company getCompanyById( @PathVariable(value = "id") int id) { return repo.findById(id); } @PostMapping("/company") @ResponseStatus(HttpStatus.CREATED) public Company addCompany( @RequestBody Company company) { return repo.save(company); } @DeleteMapping("/delete/{id}") public void deleteStudent( @PathVariable(value = "id") int id) { repo.deleteById(id); } @PutMapping("/company/{id}") public ResponseEntity<Object> updateStudent( @RequestBody Company company, @PathVariable int id) { Optional<Company> companyRepo = Optional.ofNullable( repo.findById(id)); if (!companyRepo.isPresent()) return ResponseEntity .notFound() .build(); company.setId(id); repo.save(company); return ResponseEntity .noContent() .build(); } 六、在管理系统后盾并增加以下代码。取代database_name与蕴含表的数据库公司,用户名mysql服务器的用户名(默认是root)和明码应用mysql明码。 spring.datasource.url=jdbc:mysql://localhost:3306/database_name spring.datasource.username=username spring.datasource.password=password spring.jpa.hibernate.ddl-auto=update 七、这就实现了与数据库建设连贯的过程。当初,咱们构建和运行我的项目并调用不同的api。 ...

January 15, 2022 · 2 min · jiezi

关于springboot:SpringBoot-定时任务依赖注入失败记录

前言日志零碎须要每天推送每天日志统计到钉钉群,至于如何实现向钉钉推送请参考:java(SpringBoot)实现钉钉推送。学长他们的用的是一个固定的Webhook和secrect,这样就会导致一个问题,下次批改推送群那么就须要批改源代码,于是乎我加了一个钉钉数据表,这样就能够做到随便更改推送群了。 实现过程:增加钉钉实体:次要字断:webhook、secrect /** * 钉钉 * @author hzl */@Entitypublic class Ding { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @JsonView(base.class) private Long id; private String webHook = ""; private String secret = ""; public Long getId() { return id; } public String getWebHook() { return webHook; } public void setWebHook(String webHook) { this.webHook = webHook; } public String getSecret() { return secret; } public void setSecret(String secret) { this.secret = secret; } public interface base {}}增加仓库/** * 钉钉 */@Repository("DingRepository")public interface DingRepository extends CrudRepository<Ding, Long> {}运行后果:dingRepository为空?可是我用@Autowired主动注入了啊 ...

January 14, 2022 · 1 min · jiezi

关于springboot:Spring-Boot-整合-SaToken-实现登录认证

明天分享的是 Spring Boot 整合 Sa-Token 实现登录认证。 依赖首先,咱们须要增加依赖: 要害依赖:<dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-spring-boot-starter</artifactId> <version>1.28.0</version></dependency>其余依赖:<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.fengwenyi</groupId> <artifactId>JavaLib</artifactId> <version>2.1.5</version> </dependency> <dependency> <groupId>com.fengwenyi</groupId> <artifactId>api-result</artifactId> <version>2.5.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency></dependencies>登录结构用户数据public class UserData { private static final Map<String, User> users = Map.of( "u1", new User("01", "u1", "123456", List.of("ROLE_USER")), "a2", new User("02", "a2", "123456", List.of("ROLE_ADMIN", "ROLE_USER")) ); public static class User { public String uid; public String username; public String password; public List<String> roles; public User(String uid, String username, String password, List<String> roles) { this.uid = uid; this.username = username; this.password = password; this.roles = roles; } } public static User queryByUsername(String username) { return users.get(username); } public static List<String> queryRolesByUid(String uid) { for (Map.Entry<String, User> entry : users.entrySet()) { if (uid.equals(entry.getValue().uid)) { return entry.getValue().roles; } } return null; }}登录认证@RestController@RequestMapping("/auth")public class AuthController { @PostMapping("/login") public ResponseTemplate<LoginResponseVo> login(@RequestBody @Validated LoginRequestVo requestVo) { String username = requestVo.getUsername(); String password = requestVo.getPassword(); UserData.User user = UserData.queryByUsername(username); if (Objects.isNull(user)) { return ResponseTemplate.fail("用户名不正确"); } if (!user.password.equals(password)) { return ResponseTemplate.fail("明码不正确"); } StpUtil.login(user.uid); LoginResponseVo responseVo = new LoginResponseVo() .setToken(StpUtil.getTokenValue()) ; return ResponseTemplate.success(responseVo); }}要害代码 ...

January 13, 2022 · 2 min · jiezi

关于springboot:angular-spring-boot-项目部署记录

前言日志零碎上线测试须要将我的项目部署到服务器上,上面我将分享我的实现过程。 连贯服务器SSH笔者一开始只是据说过ssh,所以最先没有想到ssh,第一反馈是去查,查出来的说是用finder(mac Os),还好老师及时禁止了我,没有去做过多的无用功。 接下来是ssh介绍:全称:Secure Shell(平安外壳协定)简略了解:给你的网络传输加了一个外壳,保障传输过程的平安。装置:mac Os,linux,win10(1803及当前)等都均反对ssh协定。验证形式:ssh用于验证的两种形式能够参考(理解):ssh的两种验证形式 根本命令:1.连贯服务器:(1)无指定端口: scp username@server 例:scp testUser@ci.testServer.com(2)指定端口:scp -P port username@server 例:scp -P 4200 testUser@ci.testServer.com (P为大写,下文亦同) 2.本地文件上传到服务器:(1)无指定端口:scp yourLocalFilePath loginUser@server:serverPath 例:scp /Users/test/Downloads/stop.sh testUser@ci.testServer.com:/usr/home/log/app/log/api(2)指定端口:scp -P port yourLocalFilePath loginUser@server:serverPath例:scp -P 3306 /Users/test/Downloads/stop.sh testUser@ci.testServer.com:/usr/home/log/app/log/api 3.本地文件夹上传到服务器:(1)无指定端口:scp -r yourLocalFilePath loginUser@server:serverPath 例:scp -r /Users/test/Downloads/stop.sh testUser@ci.testServer.com:/usr/home/log/app/log/api(2)指定端口:scp -P port -r yourLocalFilePath loginUser@server:serverPath例:scp -P 3306 -r /Users/test/Downloads/stop.sh testUser@ci.testServer.com:/usr/home/log/app/log/api 我的项目部署两大次要局部:Angular + Springboot The First: Angular部署两部曲:打包 + 上传 1.打包进入相应的前台我的项目执行ng build,那么咱们将会看到在前台我的项目中多了一个dist文件夹,如下图: 2.上传咱们只须要把dist文件夹下与前台我的项目雷同名称的文件夹上传即可,如下图web文件夹:对应scp上传命令示例:scp -P 2209 -r /Users/test/log/web/dist/web testUser@ci.testServer.com:/usr/home/test/app/test ...

January 12, 2022 · 1 min · jiezi

关于springboot:日志系统

前言三位学弟实现前台编写后,须要进行集成测试,然而这个时候我却因为无奈实现日志零碎犯了难。最初本人查来查去发现潘老师居然有这个博客,由此是让本人大略了解了这个实现过程。 日志零碎形容咱们心愿在以后零碎在产生warning或者error后,咱们可能及时的获取到错误信息,以便进行及时无效的解决。 日志零碎应运而生,他的次要性能是记录每个零碎产生指定level的状况。 我的尝试过程首先去查:如何获取日志,抉择下图圈中的(第一个是广告,能够认为他就是第一个)。 理解log4j2Log4j是Apache的一个开源我的项目,通过应用Log4j,咱们能够管制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护过程等;咱们也能够管制每一条日志的输入格局;通过定义每一条日志信息的级别,咱们可能更加粗疏地管制日志的生成过程。最令人感兴趣的就是,这些能够通过一个配置文件来灵便地进行配置,而不须要批改利用的代码。log4j2则是log4j的升级版。 log4j2应用:增加依赖 <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.7</version></dependency><dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.7</version> <type>test-jar</type> <scope>test</scope></dependency>而后我就: ERROR in ch.qos.logback.core.joran.spi.Interpreter@3:16 - no applicable action for [Appenders], current ElementPath is [[Configuration][Appenders]]ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:61 - no applicable action for [Console], current ElementPath is [[Configuration][Appenders][Console]]ERROR in ch.qos.logback.core.joran.spi.Interpreter@6:80 - no applicable action for [PatternLayout], current ElementPath is [[Configuration][Appenders][Console][PatternLayout]]ERROR in ch.qos.logback.core.joran.spi.Interpreter@9:14 - no applicable action for [Loggers], current ElementPath is [[Configuration][Loggers]]ERROR in ch.qos.logback.core.joran.spi.Interpreter@10:29 - no applicable action for [Root], current ElementPath is [[Configuration][Loggers][Root]]ERROR in ch.qos.logback.core.joran.spi.Interpreter@11:49 - no applicable action for [AppenderRef], current ElementPath is [[Configuration][Loggers][Root][AppenderRef]]查了之后发现说须要把Springboot内置的lockBack删了,删了之后又来了其余的问题:JsonView的依赖也被删了。 ...

January 10, 2022 · 2 min · jiezi

关于springboot:Flowable实战2集成Springboot

1、创立Springboot我的项目 关上IDEA,通过File -> New -> Project… -> Spring Initializr 创立一个新的Springboot我的项目 在下一个界面,填入我的项目名Name,JDK抉择8 接着,抉择Springboot 2.6.2 点击实现 生成空的Springboot我的项目,pom.xml文件内容: 2、退出Flowable依赖包 批改pom.xml文件 "properties"属性下退出: <flowable.version>6.7.2</flowable.version>留神,请确保Flowable版本与Springboot版本匹配,否则会无奈启动。查看Flowable不同版本对应的springboot版本,参考:https://blog.csdn.net/JinYJ20... "dependencies"属性下退出: <dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter</artifactId> <version>${flowable.version}</version></dependency> 这个依赖会主动向classpath增加正确的Flowable与Spring依赖。 留神:有时候,依赖JAR无奈主动获取,能够右键点击我的项目,并抉择 Maven ->Reload Project以强制手动刷新。 当初能够编写Spring Boot利用了: import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class FlowableExampleApplication { public static void main(String[] args) { SpringApplication.run(FlowableExampleApplication.class, args); }} Flowable须要数据库来存储数据。运行下面的代码会失去异样提醒,指出须要在classpath中增加数据库驱动依赖。 3、增加数据源 当初增加MySQL数据库依赖: <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.13</version></dependency>留神:MySQL依赖包版本依据本人所连贯的数据库版本批改,否则可能会连贯失败 application.properties文件中增加数据源 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/flowable?characterEncoding=UTF-8&serverTimezone=UTCspring.datasource.driverClassName=com.mysql.cj.jdbc.Driverspring.datasource.username=jinyangjiespring.datasource.password=jinyangjie 利用胜利启动后,查看数据库,能够看到,曾经主动创立了Flowable表: 留神:如果呈现“Caused by: java.lang.RuntimeException: Exception while initializing Database connection”的谬误,请确保数据源的配置项正确,并查看MySQL依赖包版本是否匹配4、REST反对4.1 增加REST依赖 通常咱们的利用会应用REST API。增加下列依赖: ...

January 8, 2022 · 2 min · jiezi