Day 033_SpringBoot
javase:OOP
mysql:持久化
html+css+js+jquery+框架:
javaweb:独立开发MVC三层架构的网站了,原始
ssm:框架,简化了我们的开发流程,配置也开始较为复杂
之前:war包,tomcat运行
spring再简化:SpringBoot:微服务架构
jar包,内嵌tomcat
服务越来越多:springcloud
-
SpringBoot
- 认识它,是什么
- 配置如何编写 yaml 语法
- 自动装配原理 :重要
- 集成web开发:业务的核心
- 集成数据库Druid
- 分布式开发:Dubbo+zookeeper
- swagger:接口文档
- 任务调度
- SpringSecurity–shiro
-
springcloud
- 微服务
- springcloud入门
- Restful
- Eureka
- Ribbon
- Feign
- HyStrix
- Zuul路由网关
- SpringCloud config:git
Spring是为了解决企业级应用开发的复杂性而创建的,简化开发。
高内聚低耦合
第一个SpringBoot程序
环境:
- jdk1.8
- maven 3.6.1
- springboot:最新版
- IDEA
官方:提供了一个快速生成的网站。IDEA集成了这个网站
-
main.java.xxx.xxxxApplication:程序的主入口,不删删改
- Application同级目录下写项目controller
-
resources.application.properties:springboot核心配置文件
-
Test.java.xxx.xxxApplicationTests:单元测试
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.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.hxh</groupId><artifactId>helloworld</artifactId><version>0.0.1-SNAPSHOT</version><name>helloworld</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><!--web依赖:tomcat dispatcherServlet xml--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--所有的springboot依赖都是使用spring-boot-starter-开头的--><!--单元测试--><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><build><!--打jar包插件--><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
- 更改tomcat默认端口号
在项目中的src/main/resources目录下创建application.properties, 在文件中写入
server.port=8989 - 更改springboot banner
在项目中的src/main/resources目录下创建banner.txt, 在文件中写入https://www.bootschool.net/ascii/
原理初探
- 自动配置:
- pom.xml
- Spring-boot-dependencies:核心依赖在父工程中
- 我们在写或者引入Springboot依赖的时候,不需要指定版本是因为有这些版本仓库
- 启动器
-
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId> </dependency>
-
启动器:说白了就是Springboot的启动场景
- 比如spring-boot-starter-web帮我们自动导入web环境所有的依赖
- Springboot会将所有的功能场景都变成一个个的启动器
- 我们要使用什么功能,就只需要找到对应的启动器就可以了 https://spring.io/projects/spring-boot#overview
-
主程序
package com.hxh;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;//SpringBootApplication:标注这个类是一个springboot的应用,启动类下的所有资源被导入 @SpringBootApplication public class Springboot01HelloworldApplication {public static void main(String[] args) {//将springboot应用启动SpringApplication.run(Springboot01HelloworldApplication.class, args);}}
注解:
-
@SpringBootApplication
-
@SpringBootConfiguration:springboot的配置
- @Configuration:spring配置类
- @Component:说明这也是Spring的组件
- @Configuration:spring配置类
-
@EnableAutoConfiguration:自动配置,自动导入包
-
@AutoConfigurationPackage:自动配置包
- @Import(AutoConfigurationPackages.Registrar.class):自动配置“包注册”
-
@Import(AutoConfigurationImportSelector.class):自动配置导入选择,选择了什么东西
-
@getAutoConfigurationEntry:或者自动配置的实体
⬇️
-
//获取所有的配置 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
-
获取候选的配置
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:自动配置的核心文件
将 类路径下 META-INF/spring.factories 里面配置的所有EnableAutoConfiguration的值加入到了容器中
⬇️
-
//获取所有的加载配置 public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {String factoryTypeName = factoryType.getName();return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); }
-
//项目资源 classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : //系统资源 ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
从spring-boot-cutoconfigure-xxx.RELEASE.jar/META-INF/spring.factories获取
//从这些资源中遍历了所有的nextElement(自动配置) while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);for (Map.Entry<?, ?> entry : properties.entrySet()) {String factoryTypeName = ((String) entry.getKey()).trim();for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {result.add(factoryTypeName, factoryImplementationName.trim());}} }
遍历完成后封装成properties供我们使用
//所有的资源加载到配置类中 Properties properties = PropertiesLoaderUtils.loadProperties(resource);
-
-
-
@ComponentScan:扫描当前主启动类同级的包
-
-
@ConditionOnClass:如果这里面的条件都满足,才会生效
结论:springboot所有的自动配置都是在启动的时候自动扫描并加载,所有的自动配置类都在spring.factories 里,但是不一定生效,要判断条件是否成立,只要导入了对应的start,就有对应的启动器,有了启动器,我们自动装配就生效,然后就配置成功
- springboot在启动的时候,从类路径下META-INF/spring.factories 获取指定的值
- 将自动配置的类导入容器,自动配置类就会生效,帮我们进行自动配置
- 以前我们需要自动配置的东西,现在springboot帮我们做了
- 整个JavaEE,解决方案和自动配置的都洗都在spring-boot-cutoconfigure-xxx.RELEASE.jar下
- 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
- 容器中也会存在非常多的xxxAutoConfiguration的文件(@Bean),就是这些类给容器中导入了这个场景需要的所有组件,并自动配置@Configuration、JavaConfig
- 有了自动配置类,免去了我们手动编写配置文件的工作
JavaConfig—@Configuration @Bean
关于Springboot,谈谈你的理解:
- 自动装配
- run();
- 判断应用类型是普通项目还是web项目
- 推断并设置main方法的定义类,找到运行的主类
- 监听器:获取上下文,处理Bean
- 全面接管SpringMVC的配置
SpringBoot配置
- 配置文件(名称是固定的):修改SpringBoot自动配置的默认值
- application.properties:key=value,只能保存键值对
- application.yaml:key:空格value,对空格的要求十分高,可以注入到配置类中
-
YAML:
name: hxh# 对象 student:name: hxhage: 3# 行内写法 student: {name: hxh,age: 3}# 数组: pets:- cat- dog- pigpets: [cat,dog,pig]
-
yaml可以直接给实体类赋值
- 第一种方法:application.yaml
在实体类中@ConfigurationProperties 会爆红产生提示,打开后可以配置xml文件,也可以不配置,不影响程序的运行
<!--导入配置文件处理器,配置文件进行绑定就会有提示--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency>
@ConfigurationProperties(prefix = "person")//与yaml中的配置 public class Person {private String name;private Integer age;private boolean happy;private Data birth;private Map<String,Object> maps;private List<Object> lists;private Dog dog; }
person:name: hxhage: 18happy: truemaps: {k1: v1,k2: v2}lists: [code,music,movie]dog:name: 旺财age: 3
@ConfigurationProperties(prefix = “person”):将配置文件中配置的每一个属性的值映射到这个组件中
- 第二种方法:自己新建个hxh.properties文件
@Component //加载指定的配置文件 @PropertySource(value = "classpath:hxh.properties") public class Person {//spel表达式取出配置文件的值@Value("${name}")//需要一个一个内容读取private String name;private Integer age;private boolean happy;private Data birth;private Map<String,Object> maps;private List<Object> lists;private Dog dog; }
javaConfig绑定配置文件的值,可以采取这些方式。
person:name: hxh${random.uuid}age: ${random.int}happy: truemaps: {k1: v1,k2: v2}lists: [code,music,movie]hello: happydog:name: ${person.hello:hello}_旺财age: 3
${person.hello:hello}:person.hello值存在取自己的值,不存的话取hello
#{random.xxx}:取随机值
-
@Value获取值和@ConfigurationProperties获取值比较
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 批量注入配置文件中的属性 | 一个个指定 |
松散绑定(松散语法) | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
-
松散绑定:yml中的last-name和类中的lastName是一样的,-后面的字母默认是大写的
-
JSR303数据校验:
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api --> <dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId> </dependency>
@Validated:数据校验
空检查
- @Null 验证对象是否为null
- @NotNull 验证对象是否不为null, 无法查检长度为0的字符串
- @NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
- @NotEmpty 检查约束元素是否为NULL或者是EMPTY.
Booelan检查
- @AssertTrue 验证 Boolean 对象是否为 true
- @AssertFalse 验证 Boolean 对象是否为 false
长度检查
- @Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
- @Length(min=, max=) Validates that the annotated string is between min and max included.
日期检查
- @Past 验证 Date 和 Calendar 对象是否在当前时间之前
- @Future 验证 Date 和 Calendar 对象是否在当前时间之后
- @Pattern 验证 String 对象是否符合正则表达式的规则
数值检查,建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为"",Integer为null
- @Min 验证 Number 和 String 对象是否大等于指定的值
- @Max 验证 Number 和 String 对象是否小等于指定的值
- @DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
- @DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
- @Digits 验证 Number 和 String 的构成是否合法
- @Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
- @Range(min=, max=) 检查数字是否介于min和max之间.
- @Range(min=10000,max=50000,message=“range.bean.wage”)
private BigDecimal wage; - @Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
- @CreditCardNumber信用卡验证
- @Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
- @ScriptAssert(lang= ,script=, alias=)
- @URL(protocol=,host=, port=,regexp=, flags=)
@Email注解报红 是因为新版本需要validation启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
结论:
-
配置文件yml还是properties他们都能获取到值;
-
如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;
-
如果说,我们专门编写了一个JavaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;
springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件
–file:./config/
–file:./
–classpath:/config/
–classpath:/
多profile文件:
-
我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties
默认使用application.properties的配置;
application.yaml(yaml只需要一个文件)
-
server:port: 8081 spring:profiles:active: prod #激活prod环境--- server:port: 8083 spring:profiles: dev---server:port: 8084 spring:profiles: prod #指定属于哪个环境
application.properties(properties需要多个application-{profile}.properties文件)
-
# Springboot 的多环境配置,可以选择激活一个配置文件 spring.profiles.active=dev
以**HttpEncodingAutoConfiguration(Http编码自动配置)**为例解释自动配置原理
/** Copyright 2012-2020 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package org.springframework.boot.autoconfigure.web.servlet;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.servlet.server.Encoding;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.filter.CharacterEncodingFilter;/*** {@link EnableAutoConfiguration Auto-configuration} for configuring the encoding to use* in web applications.** @author Stephane Nicoll* @author Brian Clozel* @since 2.0.0*/
//表示这是一个配置类
@Configuration(proxyBeanMethods = false)
//自动配置属性,指定配置哪个类 eg:ServerProperties.class
@EnableConfigurationProperties(ServerProperties.class)
//Spring的底层注解,根据不同的条件,来判断当前配置或者类是否生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)//判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnClass(CharacterEncodingFilter.class)//判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)//判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的;即使我们配置文件中不配置spring.http.encoding.enabled=true,也是默认生效的;
public class HttpEncodingAutoConfiguration {//他已经和SpringBoot的配置文件映射了private final Encoding properties;//只有一个有参构造器的情况下,参数的值就会从容器中拿public HttpEncodingAutoConfiguration(ServerProperties properties) {this.properties = properties.getServlet().getEncoding();}@Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取@ConditionalOnMissingBean //判断容器没有这个组件public CharacterEncodingFilter characterEncodingFilter() {CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();filter.setEncoding(this.properties.getCharset().name());filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));return filter;}@Beanpublic LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {return new LocaleCharsetMappingsCustomizer(this.properties);}static class LocaleCharsetMappingsCustomizerimplements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {private final Encoding properties;LocaleCharsetMappingsCustomizer(Encoding properties) {this.properties = properties;}@Overridepublic void customize(ConfigurableServletWebServerFactory factory) {if (this.properties.getMapping() != null) {factory.setLocaleCharsetMappings(this.properties.getMapping());}}@Overridepublic int getOrder() {return 0;}}}
在我们这配置文件中配置的东西,都存在一个固有的规律
- xxxAutoConfiguration:默认值 xxxProperties和配置文件绑定,我们就可以使用自定义的配置类
- 每一个这样的 xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们来做自动配置
精髓:
- SpringBoot启动会加载大量的自动配置类
- 我们看我们需要的功能有没有SpringBoot默认写好的自动配置类
- 我们再来看这个自动配置类中到底配置了哪些组件(只要我们要用的组件有,我们就不需要再来配置了)
- 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们就可以在配置文件中指定这些属性的值;
xxxxAutoConfigurartion:自动配置类,给容器中添加组件
xxxxProperties:封装配置文件中相关属性,springboot配置修改这些属性
debug: true
#日志输出,判断哪些配置类生效,哪些没有生效
SpringBoot Web开发
1. 静态资源
@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {//如果自定义一个目录:如:spring.mvc.static-pattern=/hello/,class path:/hxh/,源码会失效if (!this.resourceProperties.isAddMappings()) {logger.debug("Default resource handling disabled");return;}Duration cachePeriod = this.resourceProperties.getCache().getPeriod();CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();if (!registry.hasMappingForPattern("/webjars/**")) {customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/").setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));}String staticPathPattern = this.mvcProperties.getStaticPathPattern();if (!registry.hasMappingForPattern(staticPathPattern)) {customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));}}
- webjars:
- resources包下:resources>static>public
总结:
-
在Springboot,我们可以使用一下方式处理静态资源
- webjars localhost:8080/webjars/
- public、static、/**、resources localhost:8080/
-
resources包下优先级:resources>static(默认使用)>public
首页:index.xml放在resources/**下
更换图标:
spring.mvc.favicon.enabled=false
把图标改名为favicon.ico放在resources/**下 2.2.10之后的版本去掉这个配置,但仍可以修改
2. 模板引擎
Thymeleaf官网
Thymeleaf在Github的主页
Spring官方文档
导入Thymeleaf依赖
<dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring5</artifactId>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency><dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
配置文件:
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;public static final String DEFAULT_PREFIX = "classpath:/templates/";public static final String DEFAULT_SUFFIX = ".html";
}
classpath:/templates/xx.html
-
导入thymeleaf的名称空间
<html lang="en" xmlns:th="http://www.thymeleaf.org">
-
使用thymeleaf语法
text.xml
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <!--所有的html元素都可以被thymeleaf替换接管,th:元素名--><div h1 th:text="${msg}"></div> </body> </html>
IndexController.java
@Controller public class IndexController {@RequestMapping("/text")public String test(Model model){model.addAttribute("msg","hello,springboot");return "text";} }
Simple expressions:(表达式语法)Variable Expressions: ${...}:获取变量值;OGNL;1)、获取对象的属性、调用方法2)、使用内置的基本对象:#ctx : the context object.#vars: the context variables.#locale : the context locale.#request : (only in Web Contexts) the HttpServletRequest object.#response : (only in Web Contexts) the HttpServletResponse object.#session : (only in Web Contexts) the HttpSession object.#servletContext : (only in Web Contexts) the ServletContext object.${session.foo}3)、内置的一些工具对象:
#execInfo : information about the template being processed.
#messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax.
#uris : methods for escaping parts of URLs/URIs
#conversions : methods for executing the configured conversion service (if any).
#dates : methods for java.util.Date objects: formatting, component extraction, etc.
#calendars : analogous to #dates , but for java.util.Calendar objects.
#numbers : methods for formatting numeric objects.
#strings : methods for String objects: contains, startsWith, prepending/appending, etc.
#objects : methods for objects in general.
#bools : methods for boolean evaluation.
#arrays : methods for arrays.
#lists : methods for lists.
#sets : methods for sets.
#maps : methods for maps.
#aggregates : methods for creating aggregates on arrays or collections.
#ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样;补充:配合 th:object="${session.user}:<div th:object="${session.user}"><p>Name: <span th:text="*{firstName}">Sebastian</span>.</p><p>Surname: <span th:text="*{lastName}">Pepper</span>.</p><p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p></div>Message Expressions: #{...}:获取国际化内容Link URL Expressions: @{...}:定义URL;@{/order/process(execId=${execId},execType='FAST')}Fragment Expressions: ~{...}:片段引用表达式<div th:insert="~{commons :: main}">...</div>Literals(字面量)Text literals: 'one text' , 'Another one!' ,…Number literals: 0 , 34 , 3.0 , 12.3 ,…Boolean literals: true , falseNull literal: nullLiteral tokens: one , sometext , main ,…
Text operations:(文本操作)String concatenation: +Literal substitutions: |The name is ${name}|
Arithmetic operations:(数学运算)Binary operators: + , - , * , / , %Minus sign (unary operator): -
Boolean operations:(布尔运算)Binary operators: and , orBoolean negation (unary operator): ! , not
Comparisons and equality:(比较运算)Comparators: > , < , >= , <= ( gt , lt , ge , le )Equality operators: == , != ( eq , ne )
Conditional operators:条件运算(三元运算符)If-then: (if) ? (then)If-then-else: (if) ? (then) : (else)Default: (value) ?: (defaultvalue)
Special tokens:No-Operation: _ //分割表达式
语法规则:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<!--所有的html元素都可以被thymeleaf替换接管,th:元素名--><!--照常输出--><div th:text="${msg}"></div><!--会把<h1>转义--><div th:utext="${msg}"></div><hr><!--th:each<h3 th:each="user:${users}">[[${user}]]</h3>建议用下面的方法-->
<h3 th:each="user:${users}" th:text="${user}"></h3>
</body>
</html>
//在templates目录下的所有页面只能通过controller来跳转
//这个需要模板引擎的支持thymeleaf
@Controller
public class IndexController {@RequestMapping("/text")public String test(Model model){model.addAttribute("msg","<h1>hello,springboot</h1>");model.addAttribute("users", Arrays.asList("hxh","wang"));return "text";}
}
3. SpringMVC
SpringMVC文档
扩展视图解析器
编写一个配置类(@Configuration),是WebMvcConfigurerAdapter类型;
不能标注@EnableWebMvc
//如果你想diy一些定制化的功能,只需要写这个组件,然后将它交给bspringboot,springboot就会帮我们自动装配
//全面扩展SpringMVC dispatcherServlet
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//public interface ViewResolver 实现了视图解析器接口的类,我们就可以把它看作视图解析器@Beanpublic ViewResolver myViewResolver(){return new MyViewResolver();}//自定义类一个自己的视图解析器public static class MyViewResolver implements ViewResolver{@Overridepublic View resolveViewName(String viewName, Locale locale) throws Exception {return null;}}
}
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {// super.addViewControllers(registry);//浏览器发送 /atguigu 请求来到 successregistry.addViewController("/atguigu").setViewName("success");}
}
//如果我们要扩展SprinMvc,官方建议我们这样去做
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {//视图跳转@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/hxh").setViewName("test");}
}
- @EnableWebMvc //导入了一个类:DelegatingWebMcvConfiguration (从容器中获取所有的webmvcconfig)继承了WebMcvConfigurationSupport
- 如果含有WebMcvConfigurationSupport.class 所有的自定义配置都不生效
- 不能标注@EnableWebMvc
总结:
- 在springboot中,有非常多的xxx Configuration帮助我们进行扩展配置,只要看见了这个东西,我们就要注意了,它可能会改变spring原有的东西。
导入Lombok:
<!--Lombok-->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>
IDEA第一次导入Lombok需要安装对应插件,Preference–>plugins搜索Lombok下载安装,重启IDEA
#关闭模板引擎的缓存
spring.thymeleaf.cache=false
-
首页配置:
- 所有页面的静态资源都需要使用thymeleaf接管。
- URL使用@{}
-
页面国际化:resources/i18n下,新建文件login.properties、login_zh_CN.properties会自动合并到一个包下
-
我们需要配置i18n文件
-
我们如果需要在项目中进行按钮自动切换,我们需要自定义一个组件LocalResolver
package com.hxh.config;import org.springframework.util.StringUtils; import org.springframework.web.servlet.LocaleResolver;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Locale;public class MyLocaleResolver implements LocaleResolver {//解析请求@Overridepublic Locale resolveLocale(HttpServletRequest request) {//获取请求中的语言参数String language = request.getParameter("l");Locale locale = Locale.getDefault();//如果没有就使用默认的//如果请求的链接携带了国际化参数if (!StringUtils.isEmpty(language)){//zh_CNString[] split = language.split("_");//国家 地区locale = new Locale(split[0], split[1]);}return locale;}@Overridepublic void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {} }
-
记得将自己写的组件配置到spring容器中。@Bean
@Bean public LocaleResolver localeResolver(){return new MyLocaleResolver(); }
-
#{}
<label class="sr-only" th:text="#{login.username}">Username</label><label><input type="checkbox" value="remember-me" > [[#{login.remember}]] </label><a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a> <a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
-
-
拦截器:
//拦截器
public class LoginHandlerInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//登录成功之后应该有用户的sessoinObject loginUser = request.getSession().getAttribute("loginUser");if (loginUser==null){//没有登录request.setAttribute("msg","没有权限,请先登录");request.getRequestDispatcher("/index.html").forward(request,response);return false;//不放行}else {return true;//放行}}
}
@bean拦截器
registry.addViewController("/main.html").setViewName("dashboard");//映射@Override
public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html","/","/user/login","/asserts/css/**","/asserts/jx/**","/asserts/img/**");
}
-
员工列表展示
- 提取公共页面
-
抽取公共片段(设置侧边栏为公共片段:th:fragment=“sidebar”)将公共部分放置在commons/commons.html下,需要的直接引用
<nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar"><div class="sidebar-sticky"><ul class="nav flex-column"><li class="nav-item"><a class="nav-link active" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>Dashboard <span class="sr-only">(current)</span></a></li>
-
员工管理界面引用公共片段:insert插入replace替换
<div th:insert="commons/commons::topbar"></div> <div th:replace="~{commons/commons::sidebar}"></div>
-
如果要传递参数,可以直接使用()传参,接收判断即可
<div th:insert="~{commons/commons::sidebar(avtive='list.html')}"></div>
- 列表循环展示
-
添加员工
- 按钮提交
- 跳转到添加页面
- 添加员工成功
- 返回首页
#时间日期格式化
spring.mvc.format.date=yyyy-MM-dd
<div class="form-group"><label>department</label><!--提交的是部门的id我们在controller接收的是一个Employee,所以我们需要提交的是其中的一个属性--><select class="form-control" name="department.id"><option th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}"></option></select>
</div>
-
CRUD
-
404
-
前端:
- 模板:别人写好的,我们拿来改成自己需要的
- 框架:组件:自己手动组合拼接Bootstrap、Layui、semantic-ui
- 栅格系统
- 导航栏
- 侧边栏
- 表单
- 设计数据库(难点)
- 前端让它能够自动运行,独立化工程
- 数据接口如何对接:Json,对象all in one
- 前后端联调测试
- 有一套自己熟悉的后台模板,工作必要。推荐:x-admin
- 前端界面:至少自己能够通过前端框架组合出来一个网站页面
- 首页index
- 关于about
- blog
- 提交博客post
- 用户user
- 让这个网站能够独立运行
SpringBoot与数据访问
Spring data
JDBC
新建项目:web依赖,JDBC API,MySQL Driver
spring:datasource:username: rootpassword: 123456# 假如时区报错了,就增加一个时区的配置就ok了 erverTimezone=UTCurl: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&userUnicode=true&chctacterEncoding=utf-8driver-class-name: com.mysql.cj.jdbc.Driver
增删改查
package com.hxh.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;import java.util.List;
import java.util.Map;@RestController
public class JDBCController {@AutowiredJdbcTemplate jdbcTemplate;//查询数据库的所有信息 没有实体类,数据库中的东西,通过map获取@GetMapping("/userList")public List<Map<String,Object>> userList(){String sql = "select * from user";List<Map<String, Object>> list_maps = jdbcTemplate.queryForList(sql);return list_maps;}@GetMapping("/addUser")public String addUser(){String sql= "instert into mybatis.user(id,name,pwd) values (1,'hxh','123456')";jdbcTemplate.update(sql);return "addUser-ok";}@GetMapping("/updateUser/{id}")public String updateUser(@PathVariable("id") int id){String sql= "update mybatis.user set name=?,pwd=? where id="+id;//封装数据Object[] objects = new Object[2];objects[0] ="小明";objects[1] ="xxxxx";jdbcTemplate.update(sql,objects);return "updateUser-ok";}@GetMapping("/deleteUser/${id}")public String deleteUser(@PathVariable("id") int id){String sql= "delete from mybatis.user where id =?";jdbcTemplate.update(sql,id);return "deleteUser-ok";}
}
DRUID(重点)
导入德鲁伊的依赖
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.23</version>
</dependency>
默认配置,切换数据源 type
application.yaml
spring:datasource:username: rootpassword: Qy=UyPk%z6m9url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&userUnicode=true&chctacterEncoding=utf-8driver-class-name: com.mysql.cj.jdbc.Driver# 增加type:选择DruidDataSourcetype: com.alibaba.druid.pool.DruidDataSource
配置监控统计拦截的filters:stat监控统计、Log4j日志记录、wall防御sql注入
导入log4j依赖
dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version>
</dependency>
localhost:8080/druid
package com.hxh.config;import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.zaxxer.hikari.util.DriverDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;
import java.util.HashMap;@Configuration
public class DruidConfig {@ConfigurationProperties(prefix = "spring.datasource")@Beanpublic DataSource druidDataSource(){return new DruidDataSource();}//后台监控功能 web.xml localhost:8080/druid//因为springboot内置了servlet容器,所以没有web.xml,替代方法: ServletRegistrationBean@Beanpublic ServletRegistrationBean statViewServlet (){ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");//后台需要有人登录,账号密码配置HashMap<String, String> initParameters = new HashMap<>();//增加配置initParameters.put("loginUsername","admin");//loginUsername是固定的登录key,不能修改initParameters.put("loginPassword","123456");//loginPassword是固定的登录key,不能修改//允许谁可以访问initParameters.put("allow","");//后面的""里面为空,说明所有人都可以访问//禁止谁可以访问//initParameters.put("deny","192.168.1.12");bean.setInitParameters(initParameters);//初始化参数return bean;}//filter过滤器public FilterRegistrationBean webStartFilter(){FilterRegistrationBean bean = new FilterRegistrationBean();bean.setFilter(new WebStatFilter());//可以过滤哪些请求Map<String,String> initParameters = new HashMap<>();//这些东西不进行统计initParameters.put("exclusions","*.js,*.css,/druid/*");bean.setInitParameters(initParameters);return bean;}
}
Mybatis(重点)
整合包:Mybatis-spring-boot-starter
<!--mybatis-spring-boot-starter:整合-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.3</version>
</dependency>
数据库连接配置
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&userUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
package com.hxh.mapper;import com.hxh.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;import java.util.List;//这个注解表示了这是一个mybatis的mapper类 Dao层:@Repository
@Mapper
@Repository
public interface UserMapper {//public static final int age =18;List<User> queryUserList();User queryUserById(int id);int addUser(User user);int updateUser(User user);int deleteUser(int id);
}
整合mybatis
#整合mybatis
mybatis.type-aliases-package=com.hxh.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
一个基于 XML 映射语句的示例,它应该可以满足UserMapper 的调用
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hxh.mapper.UserMapper"><select id="queryUserList" resultType="User">select * from user</select><select id="queryUserById" resultType="User">select * from user where id = #{id}</select><insert id="addUSer" parameterType="User">insert into User (id,name,pwd) values (#{id},#{name},#{pwd})</insert><update id="updateUser" parameterType="User">update user set name=#{name},pwd=#{pwd} where id=#{id}</update><delete id="deleteUser" parameterType="User">delete from user where id = #{id}</delete></mapper>
增删改查
package com.hxh.controller;import com.hxh.mapper.UserMapper;
import com.hxh.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
public class UserController {@Autowiredprivate UserMapper userMapper;@GetMapping("/queryUserList")public List<User> queryUserList(){List<User> userList = userMapper.queryUserList();for (User user : userList){System.out.println(user);}return userList;}//增加一个用户@GetMapping("/addUser")public String addUser(){userMapper.addUser(new User(5,'h',1234));return "add";}//修改一个用户@GetMapping("/updateUser")public String updateUser(){userMapper.updateUser(new User(5,'jxj',1234));return "update";}//删除一个用户@GetMapping("/deleteUser")public String deleteUser(){userMapper.deleteUser(5);return "delete";}
}
M:model模型:数据和业务
V:view视图:HTML
C:controller控制器:交接
步骤:
- 导入包
- 配置文件
- mybatis配置
- 编写sql
- service业务层调用dao层
- controller调用service层
SpringSecurity
在web开发中,安全第一位:过滤器,拦截器
功能性需求:否
安全框架:
-
shiro
-
springsecurity
-
功能:认证(登录)、授权(VIP1、VIP2)
-
功能权限
-
访问权限
-
菜单权限
MVC—Spring—SpringBoot—框架思想
1. 简介
Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!
记住几个类:
- WebSecurityConfigurerAdapter:自定义Security策略
- AuthenticationManagerBuilder:自定义认证策略
- @EnableWebSecurity:开启WebSecurity模式
- @Enablexxxx:开启某个功能
Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)
- “认证”(Authentication)
-
身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。
-
身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。
- “授权” (Authorization)
- 授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。
这个概念是通用的,而不是只在Spring Security 中存在。
2. 认证和授权
-
引入 Spring Security 模块
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId> </dependency>
-
配置认证和授权
-
package com.hxh.config;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import javax.annotation.security.PermitAll;//AOP @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {//授权、链式编程@Overrideprotected void configure(HttpSecurity http) throws Exception {//首页所有人可以访问,功能页只有对应有权限的人才能访问//请求授权的规则http.authorizeRequests().antMatchers("/").permitAll().antMatchers("/level1/**").hasRole("vip1").antMatchers("/level2/**").hasRole("vip2").antMatchers("/level3/**").hasRole("vip3");//没有权限默认回到登录页,需要开启登录的页面http.formLogin();//开启了注销功能,并注销成功后返回首页 http.logout().logoutSuccessUrl("/");}//认证//没有加密时(注释掉的方法)运行提示犯错误,密码编码:PasswordEncoder //在Spring Security 5.0+ 新增了很多的加密方法,需要把密码加密@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {//这些数据正常应该从数据库中获取//auth.jdbcAuthentication() 从数据库认证 // auth.inMemoryAuthentication() //从内存认证 // .withUser("hxh").password("123456").roles("vip2","vip3") // .and() // .withUser("root").password("123456").roles("vip1","vip2","vip3") // .and() // .withUser("guest").password("123456").roles("vip1");auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) //从内存认证.withUser("hxh").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3").and().withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3").and().withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");} }
-
security与thymeleaf整合包
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 --> <dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity5</artifactId><version>3.0.4.RELEASE</version> </dependency>
http.csrf().disable();//关闭csrf功能,跨站请求伪造,默认只能通过post方式提交logout请求 http.rememberMe();//记住我
Shiro
- Apache Shiro是一个java的安全(权限)框架
- Shiro可以非常容易的开发出足够好的应用,其不仅可以用在javaSE环境,也可以用在javaEE环境
- Shiro可以完成认证、授权、加密、会话管理、web集成、缓存等
- 下载地址
-
导入maven依赖
默认使用commons-logging
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.4.1</version> </dependency> <!-- Shiro uses SLF4J for logging. We'll use the 'simple' bindingin this example app. See http://www.slf4j.org for more info. --> <dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.21</version></dependency> <dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>1.7.21</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version> </dependency>
使用log4j
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-08-shiro</artifactId><groupId>com.hxh</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>hello-shiro</artifactId><dependencies><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.4.2</version></dependency><!-- configure logging --><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>1.5.6</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.5.6</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.14</version></dependency></dependencies> </project>
-
配置文件
Log4j.propeties
# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # log4j.rootLogger=INFO, stdoutlog4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n# General Apache libraries log4j.logger.org.apache=WARN# Spring log4j.logger.org.springframework=WARN# Default Shiro logging log4j.logger.org.apache.shiro=INFO# Disable verbose logging log4j.logger.org.apache.shiro.util.ThreadContext=WARN log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
shiro.ini,需要下载ini插件
# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # ============================================================================= # Quickstart INI Realm configuration # # For those that might not understand the references in this file, the # definitions are all based on the classic Mel Brooks' film "Spaceballs". ;) # =============================================================================# ----------------------------------------------------------------------------- # Users and their assigned roles # # Each line conforms to the format defined in the # org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc # ----------------------------------------------------------------------------- [users] # user 'root' with password 'secret' and the 'admin' role root = secret, admin # user 'guest' with the password 'guest' and the 'guest' role guest = guest, guest # user 'presidentskroob' with password '12345' ("That's the same combination on # my luggage!!!" ;)), and role 'president' presidentskroob = 12345, president # user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz' darkhelmet = ludicrousspeed, darklord, schwartz # user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz' lonestarr = vespa, goodguy, schwartz# ----------------------------------------------------------------------------- # Roles with assigned permissions # # Each line conforms to the format defined in the # org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc # ----------------------------------------------------------------------------- [roles] # 'admin' role has all permissions, indicated by the wildcard '*' admin = * # The 'schwartz' role can do anything (*) with any lightsaber: schwartz = lightsaber:* # The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with # license plate 'eagle5' (instance specific id) goodguy = winnebago:drive:eagle5
-
HelloWorld
Quickstart.java
/** Licensed to the Apache Software Foundation (ASF) under one* or more contributor license agreements. See the NOTICE file* distributed with this work for additional information* regarding copyright ownership. The ASF licenses this file* to you under the Apache License, Version 2.0 (the* "License"); you may not use this file except in compliance* with the License. You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing,* software distributed under the License is distributed on an* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY* KIND, either express or implied. See the License for the* specific language governing permissions and limitations* under the License.*/import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.slf4j.Logger; import org.slf4j.LoggerFactory;/*** Simple Quickstart application showing how to use Shiro's API.** @since 0.9 RC2*/ public class Quickstart {private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);public static void main(String[] args) {// The easiest way to create a Shiro SecurityManager with configured// realms, users, roles and permissions is to use the simple INI config.// We'll do that by using a factory that can ingest a .ini file and// return a SecurityManager instance:// Use the shiro.ini file at the root of the classpath// (file: and url: prefixes load from files and urls respectively):Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");SecurityManager securityManager = factory.getInstance();// for this simple example quickstart, make the SecurityManager// accessible as a JVM singleton. Most applications wouldn't do this// and instead rely on their container configuration or web.xml for// webapps. That is outside the scope of this simple quickstart, so// we'll just do the bare minimum so you can continue to get a feel// for things.SecurityUtils.setSecurityManager(securityManager);// Now that a simple Shiro environment is set up, let's see what you can do:// get the currently executing user:获取当前的用户对象SubjectSubject currentUser = SecurityUtils.getSubject();// Do some stuff with a Session (no need for a web or EJB container!!!)//通过当前用户拿到sessionSession session = currentUser.getSession();session.setAttribute("someKey", "aValue");String value = (String) session.getAttribute("someKey");if (value.equals("aValue")) {log.info("Retrieved the correct value! [" + value + "]");}// let's login the current user so we can check against roles and permissions://判断当前的用户是否被认证if (!currentUser.isAuthenticated()) {//Token:令牌,UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");token.setRememberMe(true);try {currentUser.login(token);//执行了登录操作} catch (UnknownAccountException uae) {log.info("There is no user with username of " + token.getPrincipal());} catch (IncorrectCredentialsException ice) {log.info("Password for account " + token.getPrincipal() + " was incorrect!");} catch (LockedAccountException lae) {log.info("The account for username " + token.getPrincipal() + " is locked. " +"Please contact your administrator to unlock it.");}// ... catch more exceptions here (maybe custom ones specific to your application?catch (AuthenticationException ae) {//unexpected condition? error?}}//say who they are://print their identifying principal (in this case, a username):log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");//test a role:if (currentUser.hasRole("schwartz")) {log.info("May the Schwartz be with you!");} else {log.info("Hello, mere mortal.");}//粗粒度//test a typed permission (not instance-level)if (currentUser.isPermitted("lightsaber:wield")) {log.info("You may use a lightsaber ring. Use it wisely.");} else {log.info("Sorry, lightsaber rings are for schwartz masters only.");}//细粒度//a (very powerful) Instance Level permission:if (currentUser.isPermitted("winnebago:drive:eagle5")) {log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " +"Here are the keys - have fun!");} else {log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");}//注销//all done - log out!currentUser.logout();//结束System.exit(0);} }
-
获取当前的用户对象Subject
Subject currentUser = SecurityUtils.getSubject(); -
通过当前用户拿到session
Session session = currentUser.getSession(); -
判断当前的用户是否被认证
currentUser.isAuthenticated() -
获得当前用户的认证
currentUser.getPrincipal()
-
当前用户是否拥有什么角色 eg:schwartz
currentUser.hasRole(“schwartz”)
-
当前用户的权限
currentUser.isPermitted(“lightsaber:wield”)
-
注销
currentUser.logout();
-
SpringBoot中集成:
-
Shiro架构
-
Application Code➡️Subject(用户)
⬇️
-
Shiro SecurityManager(管理所有用户)
⬇️
- Realm(连接数据)
-
-
Shiro整合spring的包
-
创建Realm
package com.hxh.config;import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection;//自定义的Realm public class UserRealm extends AuthorizingRealm {//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("执行了授权doGetAuthorizationInfo");return null;}//认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println("执行了认证doGetAuthenticationInfo");return null;} }
-
配置
package com.hxh.config;import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration public class ShiroConfig {@Bean//ShiroFilterFactoryBean 第三步public ShiroFilterFactoryBean getshiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();//设置安全管理器bean.setSecurityManager(defaultWebSecurityManager);return bean;}//DefaultWebSecurityManager 第二步@Bean(name = "securityManager")public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();//关联UserRealmsecurityManager.setRealm(userRealm);return securityManager;}//创建realm对象,需要自定义 第一步@Beanpublic UserRealm userRealm(){return new UserRealm();}}
-
拦截
@Bean//ShiroFilterFactoryBean 第三步public ShiroFilterFactoryBean getshiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();//设置安全管理器bean.setSecurityManager(defaultWebSecurityManager);//添加shiro的内置过滤器/*anon:无需认证就可以访问authc:必须认证了才能访问user:必须拥有记住我功能才能用perms:拥有对某个资源的权限才能访问role:拥有某个角色权限才能访问*/Map<String, String> filterMap = new LinkedHashMap<>(); // filterMap.put("/user/add","authc"); // filterMap.put("/user/update","authc");//使用通配符也是可以的filterMap.put("/user/*","authc");bean.setFilterChainDefinitionMap(filterMap);//设置登录的请求bean.setLoginUrl("/toLogin");return bean;}
Swagger
Swagger简介
前后端分离
Vue+SpringBoot
后端时代:前端只用管理静态页面:html,后端通过模板引擎JSP,后端是主力
前后端分离式时代:
- 后端:后端控制层Controller,服务层Service,数据访问层Dao
- 前端:前端控制层,视图层
- 伪造后端数据,json,已经存在,不需要后端,前端工程依旧能够跑起来
- 前后端如何交互?API
- 前后端相对独立,松耦合
- 前后端甚至可以部署在不同的服务器上
产生一个问题:
- 前后端集成联调,前端人员和后端人员无法做到及时协商,需要尽早解决。
解决方法:
- 首先制定一个schema(计划的提纲),实时更新最新API,降低集成风险
- 早些年:指定word计划文档
- 前后端分离:
- 前端测试后端接口:postman
- 后端提供接口,需要实时更新最新的消息及改动
Swagger
- 号称世界上最流行的API框架
- RestFul API 文档在线生成工具:API文档与API定义同步更新
- 直接运行,可以在线测试API接口
- 支持多种语言(Java、Php……)
官网
在项目中使用Swagger需要springbox:
- swagger2
- swagger-ui
SpringBoot集成Swagger
-
新建一个SpringBoot-web项目
-
导入相关依赖
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version> </dependency><!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui --> <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version> </dependency>
-
编写一个Hello工程
src–>main–>java–>controller–>controller.java
package com.hxh.swagger.controller;import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;@RestController public class Controller {@RequestMapping(value = "/hello")public String hello(){return "hello";} }
-
配置Swagger
config–>SwaggerConfig.java
package com.hxh.swagger.config;import org.springframework.context.annotation.Configuration; import springfox.documentation.swagger2.annotations.EnableSwagger2;@Configuration @EnableSwagger2//开启Swagger2 public class SwaggerConfig {}
-
测试运行
http://localhost:8080/swagger-ui.html 导入的依赖使用2.9.2版本,使用3.0.0版本访问不了
四部分:Swagger信息,接口信息,实体类信息,右上角的组
配置Swagger
Swagger的bean实例Docket
package com.hxh.swagger.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;import java.util.ArrayList;@Configuration
@EnableSwagger2//开启Swagger2
public class SwaggerConfig {//配置Swagger的Docket的Bean实例@Beanpublic Docket docket(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());}//配置Swagger信息 apiInfo http://localhost:8080/swagger-ui.html 界面显示⬇️private ApiInfo apiInfo(){Contact contact = new Contact("hxh", "http://www.hxh.com", "1234567@123.com");//作者信息return new ApiInfo("hxh的Swagger API文档","有更热爱的事了","v1.0","http://www.hxh.com",contact,"Apache 2.0","http://www.apache.org/licenses/LICENSE-2.0",new ArrayList());}
}
Swagger配置扫描接口
Docket.select()
public class SwaggerConfig {//配置Swagger的Docket的Bean实例@Beanpublic Docket docket(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()//RequestHandlerSelectors配置要扫描接口的方式.apis(RequestHandlerSelectors.basePackage("com.hxh.swagger.controller")) //basePackage指定要扫描的包
// .apis(RequestHandlerSelectors.any()) //any:扫描全部
// .apis(RequestHandlerSelectors.none()) //none都不扫描
// .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class)) //withClassAnnotation扫描类上的注解,参数是一个注解的反射对象
// .apis(RequestHandlerSelectors.withMethodAnnotation(GetMapping.class)) //withMethodAnnotation扫描方法上的注解//过滤什么路径.paths(PathSelectors.ant("/hxh/**")).build();}
配置是否启动Swagger
public class SwaggerConfig {@Beanpublic Docket docket(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).enable(false)//是否启用Swagger,如果为false则不能在浏览器中访问Swagger.select().apis(RequestHandlerSelectors.basePackage("com.hxh.swagger.controller")).build();}
我只希望我的Swagger在生产环境中使用,在发布时不使用:
-
判断是否是生产环境 flag=false
-
注入enable()
@Configuration @EnableSwagger2 public class SwaggerConfig {//配置Swagger的Docket的Bean实例@Beanpublic Docket docket(Environment environment){//设置要显示的Swagger环境Profiles profiles =Profiles.of("dev","test");//通过environment.acceptsProfiles判断是否处在自己设定的环境当中boolean flag = environment.acceptsProfiles(profiles);return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).enable(flag).select().apis(RequestHandlerSelectors.basePackage("com.hxh.swagger.controller")).build(); }
配置API文档的分组
@Configuration
@EnableSwagger2//开启Swagger2
public class SwaggerConfig {//配置Swagger的Docket的Bean实例@Beanpublic Docket docket(Environment environment){//设置要显示的Swagger环境Profiles profiles =Profiles.of("dev","test");//通过environment.acceptsProfiles判断是否处在自己设定的环境当中boolean flag = environment.acceptsProfiles(profiles);return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).groupName("韩小花")//配置API文档的分组(swagger-ui.html右上角的组).enable(flag).select().apis(RequestHandlerSelectors.basePackage("com.hxh.swagger.controller")).build();
}
如何配置多个分组:多个Docket实例
@Configuration
@EnableSwagger2//开启Swagger2
public class SwaggerConfig {@Beanpublic Docket docket1(){return new Docket(DocumentationType.SWAGGER_2).groupName("A");}@Beanpublic Docket docket2(){return new Docket(DocumentationType.SWAGGER_2).groupName("B");}@Beanpublic Docket docket3(){return new Docket(DocumentationType.SWAGGER_2).groupName("C");}
}
实体类配置:
package com.hxh.swagger.pojo;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;//实体类共三个:@Api @ApiModel @ApiModelProperty
//@Api(注释)
@ApiModel("用户实体类")//生成的加个注释
public class User {@ApiModelProperty("用户名")public String username;@ApiModelProperty("密码")public String password;}
controller:
package com.hxh.swagger.controller;import com.hxh.swagger.pojo.User;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class HelloController {@GetMapping(value = "/hello")public String hello(){return "hello";}//只要我们的接口返回值中存在实体类,它就会被扫描到Swagger@PostMapping("/user")public User user() {return new User();}//Operation接口,不是放在类上的,是方法@ApiOperation("hello控制类")@GetMapping(value = "/hello2")public String hello2(@ApiParam("用户名") String username){return "hello"+username;}@ApiOperation("post测试类")@PostMapping(value = "/postt")public User postt(@ApiParam("用户名") User user){int i = 5/0;//500的错误return user;}
}
总结:
- 我们可以通过Swagger给一些比较难理解的属性或者接口增加注释信息
- 接口文档实时更新
- 可以在线测试
【注意点】出于安全考虑,节省内存的运行,在正式发布时关闭Swagger,
任务
-
异步任务
package com.hxh.springboot09.service;import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service;@Service public class AsyncService {//告诉Spring这是一个异步的方法@Asyncpublic void hello(){try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("数据正在处理");} }
try catch快捷键:option+command+t
package com.hxh.springboot09;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync;@EnableAsync//开启异步注解功能 @SpringBootApplication public class Springboot09TestApplication {public static void main(String[] args) {SpringApplication.run(Springboot09TestApplication.class, args);}}
-
定时任务
TaskScheduler:任务调度者
TaskEcecutor:任务执行者
@EnableScheduling:开启定时功能的注解。放在核心main方法上
@Scheduled:表示什么时候执行
Cron表达式:eg: https://www.cnblogs.com/junrong624/p/4239517.html
package com.hxh.springboot09.service;import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service;@Service public class ScheduledService {//在一个特定的时间执行这个方法 Timer//Cron表达式//秒 分 时 日 月 星期(0-7均表示星期日)@Scheduled(cron = "0 32 11 * * ?") // @Scheduled(cron = "0 32 11 * * ?")//每天11点32分执行一次 // @Scheduled(cron = "30 0/5 10,18 * * ?")//每天10点和18点,每隔5分钟执行一次 // @Scheduled(cron = "0 15 10 ? * 1-6")//每个月的周一到周六十点十五分执行一次public void hello(){System.out.println("你被执行了");} }
-
邮件发送(JavaWeb中有讲email,SpringBoot里面发送邮件比较简单)
-
导入包
<!--javax.mail--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId> </dependency>
-
编写配置
# 设置邮箱号 spring.mail.username=*****@qq.com # QQ邮箱设置-账户-开启pop3,生成密码 spring.mail.password=**** spring.mail.host=smtp.qq.com # qq要开启加密验证,其他的不需要 spring.mail.properties.mail.smtp.ssl.enable=true
-
@Autowired自动注入一个邮件发送
package com.hxh.springboot09;import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.mail.MailMessage; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.mail.javamail.MimeMessageHelper;import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import java.io.File;@SpringBootTest class Springboot09TestApplicationTests {@AutowiredJavaMailSenderImpl mailSender; // @Test // void contextLoads() { // //一个简单的邮件 // SimpleMailMessage mailMessage = new SimpleMailMessage(); // mailMessage.setSubject("感谢"); // mailMessage.setText("感谢你很努力"); // mailMessage.setTo("****@qq.com"); // mailMessage.setFrom("****@qq.com"); // mailSender.send(mailMessage); // }@Testvoid contextLoads() throws MessagingException {//一个复杂的邮件MimeMessage mimeMessage = mailSender.createMimeMessage();//组装MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);//主题helper.setSubject("你好");//正文helper.setText("<p style='color:red'>你已经很棒了</p>",true);//附件helper.addAttachment("1.jpg",new File("/Users/hxh/Desktop/1.jpg"));helper.addAttachment("2.jpg",new File("/Users/hxh/Desktop/1.jpg"));helper.setTo("****@qq.com");helper.setFrom("****@qq.com");mailSender.send(mimeMessage);}}
封装
/*** * @param html* @param subject* @param text* @throws MessagingException* @Author hxh*/ public void sendMail(Boolean html,String subject,String text) throws MessagingException {//一个复杂的邮件MimeMessage mimeMessage = mailSender.createMimeMessage();//组装MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,html);//主题helper.setSubject(subject);//正文helper.setText(text,true);//附件helper.addAttachment("1.jpg",new File("/Users/hxh/Desktop/1.jpg"));helper.addAttachment("2.jpg",new File("/Users/hxh/Desktop/1.jpg"));helper.setTo("***@qq.com");helper.setFrom("***@qq.com");mailSender.send(mimeMessage); }
-
分布式 Dubbo+Zookeeper+SpringBoot
Dubbo
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nuwA1bcz-1597482381111)(/Users/hxh/Desktop/hxh/note/picture/dubbo.png)]
前台 中台 后台
zookeeper:注册中心
dubbo-admin:是一个监控管理后台,查看我们注册了哪些服务,哪些服务被消费了(可以不要)
Dubbo:jar包
zookeeper及其依赖包,解决日志冲突,还需要剔除日志依赖
<!--导入Dubbo+zookeeper-->
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-spring-boot-starter -->
<dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.8</version>
</dependency><!--zkclient,日志会冲突,需要引入-zookeeper-->
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency><groupId>com.github.sgroschupf</groupId><artifactId>zkclient</artifactId><version>0.1</version>
</dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>5.1.0</version>
</dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>5.1.0</version>
</dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.6.1</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions>
</dependency>
总结
开发框架:
-
spring
- IOC AOP
- IOC:控制反转,原来我们都是一步步自己操作,现在交给容器,我们需要什么直接去拿就可以
- AOP:切面(本质动态代理)
- 不影响业务本来的情况下实现动态增加功能,大量应用在日志、事务等方面
- Spring是一个轻量级的Java开源框架,容器
- 目的:解决企业开发的复杂性问题
- IOC AOP
-
SpringBoot
- SpringBoot是Spring的升级版
- 新一代JavaEE的开发标准,开箱即用,拿过来就可以用
- 自动配置
- 特性:约定大于配置
随着公司体系越来越大,用户越来越多
- 微服务架构(新架构)
- 模块化,功能化
- 人过于多,一台服务器解决不了,增加服务器,横向解决问题
- 假设A服务器占用98%,B服务器只占用了10%-------均衡,负载均衡
- 将原来的整体项目分成模块化,用户就是一个单独的项目,签到也是一个单独的项目,项目和项目之间需要通信
- 用户非常多而签到十分少,给用户多一点服务器,给签到少一点服务器
微服务架构问题
-
分布式架构会遇到的四个核心问题
- 这么多服务,客户端该如何去访问
- 这么多服务,服务之间如何进行通信
- 这么多服务,如何治理
- 服务挂了,怎么办
-
解决方案
- SpringCloud是一套生态,就是来解决以上分布式架构的四个问题
- 使用SpringCloud必须掌握SpringBoot,SpringCloud是基于SpringBoot
-
Spring Cloud NetFlix,出来了一套解决方案。一站式解决方案,我们都可以直接用
API网关
Feigh----HTTPClient------HTTP的通信方式,同步并阻塞
服务注册与发现 Eureka
熔断机制 Hystrix
2018年年底,NetFlix宣布无限期停止维护,生态不再维护,就会脱节
-
Apache Dubbo zookeeper 第二套解决系统
API:没有。要么找第三方组件,要么自己实现
Dubbo是一个高性能的基于Java实现的RPC通信框架
服务注册与发现:zookeeper:动物园管理者(Hadoop,Hive)
熔断机制:没有。借助了Hystrix
-
SpringCloud Alibaba 一站式解决方案
-
目前又提出一种方法:
服务网格:下一代微服务标准,Service Mesh
代表解决方案:Istio
- API网关
- HTTP、RPC框架,异步调用
- 服务注册与发现,高可用
- 熔断机制,服务降级
为什么要解决这个问题?本质:网络不可靠
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- rstp环境搭建
1. 安装ffmpeg yum install -y gcc gcc-c++安装yasm:yasm-1.3.0 安装包:ffmpeg-4.3.1tar zxvf yasm-1.3.0.tar.gz cd yasm-1.3.0./configuremakemake installcdcd ffmpeg-4.3.1./configuremakemake install#测试是否安装成功ffmpeg2.安装nginx yum install -y libtool安装包:…...
2024/4/29 23:33:10 - 异步编程之Future那堆事
有三种 submit。这三种按照提交任务的类型来算分为两个类型。提交执行 Runnable 类型的任务提交执行 Callable 类型的任务他们都是返回Future类型 看一下 Callable 类型的任务是怎么回事;注意这个方法,一会会对比到;接下来再说说 submit 的任务为 Runable 类型的情况① 的方法扔…...
2024/5/2 7:19:45 - 一文读懂目标检测之R-CNN系列,YOLO,SSD
一、目标检测常见算法 object detection,就是在给定的图片中精确找到物体所在位置,并标注出物体的类别。所以,object detection要解决的问题就是物体在哪里以及是什么的整个流程问题。 然而,这个问题可不是那么容易解决的,物体的尺寸变化范围很大,摆放物体的角度,姿态不…...
2024/4/29 23:33:01 - Java基础面试题 (2020持续更新)
1.面向对象和面向过程的区别 面向过程优点: 性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗 资源;比如单片机、嵌入式开发、Linux/Unix 等一般采用面向过程开发,性能是 最重要的因素。 缺点: 没有面向对象易维护、易复用、易扩展面向对象优点: 易维护、易…...
2024/5/3 20:55:19 - 软件测试--Linux学习
Linus一切皆文件Linux内核Linux是一个操作系统 Linux内核是操作系统的核心 Linux内核版本号由3个数字组成:r,x,y r:目前发布的内核主版本 x:偶数表示稳定版本,奇数表示开发中版本 y:错误修补的次数 以版本号为例:4.4.9-5.ELsmp r:4,主版本号;x:4,次版本号,表示稳定版本…...
2024/4/29 1:16:18 - Metasploit技术初入门03
上一篇我们了解到了后期渗透模块的工具meterpreter,主要集中在信息收集的阶段,现在开始信息收集之后的权限提升。 权限提升 一般情况下刚开始得到shell的时候都是guest或者user权限,权限级别比较低。为了能做更多的事,比如获取hash,安装软件,修改防火墙,修改注册表等,就…...
2024/5/5 14:21:44 - 在Maya和ZBrush中制作出逼真的海盗
今天来分享一下海盗作品的制作过程,本教程是有关创建逼真渲染角色(从参考收集到最终姿势和渲染)的一般指南。我将展示在Maya和ZBrush中进行建模和摆姿势的总体过程。海盗的 最终渲染 参考 第一次收集参考资料时,我确定了海盗角色最重要的细节,并对我的照片进行了分类(身体…...
2024/4/29 23:32:54 - cookie、localStorage、sessionStorage、session
简介在以前经常用到的cookie、session,但在H5中新引入了新的浏览器本地缓存方案。因为大家使用的不太规范用来作为本地储存工具,在下次请求时会默认带上cookie中的数据导致浪费性能和流量。下面就从开始介绍为什么产生的cookie,它的出现是为了解决什么问题,它有什么问题;后…...
2024/5/6 19:11:43 - (已解决)vmware15安装失败 —— faild to generate ssl key...
vmware15安装失败原因最终解决原因 今天早上系统崩溃了(win10),中午重装了以后还没配几个软件,装到 vmware 的时候安装失败,提示无法生成ssl密钥。(这个安装包是之前用过的,没碰到啥问题) 尝试了安装 C++ 2017 —— 失败尝试在cmd里输入 openssl ,发现电脑里已经装过…...
2024/4/29 23:32:46 - 【 rbx1翻译 第七章、控制移动基座】第八节、使用里程计进行往返运动
7.8 Out and Back Using Odometry (使用里程计进行往返运动) 现在,我们了解了里程表信息是如何在ROS中表示的,我们可以更精确地在往返过程中移动机器人。 下一个脚本将监视/ odom和/ base_link坐标系之间的转换报中的机器人的位置和方向,而不是根据时间和速度来猜测距离和角…...
2024/4/29 23:32:43 - ElasticSearch启动报错,bootstrapchecksfailed
修改elasticsearch.yml配置文件,允许外网访问。vim config/elasticsearch.yml# 增加network.host: 0.0.0.0启动失败,检查没有通过,报错[2018-05-18T17:44:59,658][INFO ][o.e.b.BootstrapChecks ] [gFOuNlS] bound or publishing to a non-loopback address, enforcing b…...
2024/4/29 23:32:41 - iOS设备数据恢复软件Apeaksoft iOS Toolkit Mac
iOS Toolkit Mac版是Apeaksoft系列数据恢复套件中的一款iOS设备数据恢复软件,Apeaksoft iOS Toolkit Mac破解版能够帮助用户恢复各种数据文件,无论是因为意外删除,系统崩溃,格式化还是掉入水里,iOS Toolkit Mac版都能够为您进行数据恢复!Apeaksoft iOS Toolkit for Mac以…...
2024/4/29 23:32:34 - 从零开始游戏开发笔记(0):前期准备
从零开始游戏开发笔记(0):前期准备(持续更新中)一、开发软件1.1 游戏引擎1.2 美工软件1.3 音乐软件1.4 插件二、教程、素材1.1 学习教程1.2 素材网站三、其他技能3.1 编程3.2游戏策划四、开发流程 一、开发软件 1.1 游戏引擎 游戏引擎是制作游戏的核心工具,将各个阶段的成…...
2024/4/29 23:32:30 - B - Longest Ordered Subsequence(动态规划)
传送门 B - Longest Ordered Subsequence A numeric sequence of ai is ordered if a1 < a2 < … < aN. Let the subsequence of the given numeric sequence (a1, a2, …, aN) be any sequence (ai1, ai2, …, aiK), where 1 <= i1 < i2 < … < iK <=…...
2024/4/29 23:32:25 - Git 对已经加入版本控制(add)的文件,修改后不提交方法
# 执行命令将db.php加入不提交队列git update-index --assume-unchanged code/Pcb-service/pcb-web/src/main/resources/application.yml# 执行命令将db.php取消加入不提交队列git update-index --no-assume-unchanged code/Pcb-service/pcb-web/src/main/resources/applicat…...
2024/4/29 23:32:22 - 中阶算法---递归(1)
谈到递归,不得不说起汉诺塔,其实现代码如下: //include<bits/stdc++.h> #include <iostream> #include<cstdio> using namespace std; void fun(int n,char a,char b,char c){if(n==1){printf("Move %d from %c to %c\n",n,a,c);}else{fun(n-1,…...
2024/5/1 23:01:18 - Java---API之Object类( jdk1.8中文 百度翻译版 帮助文档)
API–Application Programming Interface(提供一系列的接口以及接口下的类) 快速查找步骤指引: 1.点击索引,输入object(输入自己需要查看的类名即可),回车2.默认选择第一个,点击显示3.这边关于object类里的所有方法都会显示出来了API里提供的所有方法要么被protected修饰…...
2024/4/29 23:32:15 - C语言学习笔记(2)——调用函数
本文主要介绍了C语言学习中调用函数的基础内容,涉及了函数调用的相关知识,并介绍了函数的嵌套调用和递归调用。 1.调用函数 1.1 函数调用的一般形式有三种:(1)函数调用语句,如“printf_star();”。(2)函数表达式。(3)函数参数。 1.2函数调用的过程。 (1)未进行函数…...
2024/4/29 23:32:10 - JavaScript重点
JavaScript重点JavaScript有几种数据类型 Null类型的值有几个,表示什么 Undefined类型的值有几个,表示什么 其他数据类型转为String类型的三种方式 其他数据类型转为Number类型的四种方式 其他数据类型转为Boolean类型的两种方式 创建对象的两种方式 如何判断一个对象中是否含…...
2024/4/29 23:32:06 - 保险基本概念测试人员须知(一)
保险基本概念测试人员须知(一)提示:保险基本概念熟知对初入保险行业的测试人员面试及日后工作有一定的帮助目录保险基本概念测试人员须知(一)内容:新契约名词保险契约:契约要素:投保人保险人保险费保险费率标准保费趸交保费经过保费保险金额寿险风险保额累计寿险风险保…...
2024/4/29 7:58:19
最新文章
- C++构造函数和析构函数的调用顺序
一般情况下,调用析构函数的次序正好与调用构造函数的次序相反,也就是最先被调用的构造函数,其对应的析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。 当然对象的构造函数和析构函数调用时机和…...
2024/5/7 2:04:30 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/5/6 9:38:23 - Docker Desktop+WSL2安装到自定义路径
现在大多数软件实在太“流氓”了,在安装过程中,根本不让你选择安装路径,默认安装到$HOME下(windows C盘),随着软件的使用增多,可能磁盘空间不够,这个时候就想着,看看某些…...
2024/5/6 2:23:47 - HIS系统是什么?一套前后端分离云HIS系统源码 接口技术RESTful API + WebSocket + WebService
HIS系统是什么?一套前后端分离云HIS系统源码 接口技术RESTful API WebSocket WebService 医院管理信息系统(全称为Hospital Information System)即HIS系统。 常规模版包括门诊管理、住院管理、药房管理、药库管理、院长查询、电子处方、物资管理、媒体管理等&…...
2024/5/5 8:48:17 - 416. 分割等和子集问题(动态规划)
题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义:dp[i][j]表示当背包容量为j,用前i个物品是否正好可以将背包填满ÿ…...
2024/5/6 18:23:10 - 【Java】ExcelWriter自适应宽度工具类(支持中文)
工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...
2024/5/6 18:40:38 - Spring cloud负载均衡@LoadBalanced LoadBalancerClient
LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon,直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件,我们讨论Spring负载均衡以Spring Cloud2020之后版本为主,学习Spring Cloud LoadBalance,暂不讨论Ribbon…...
2024/5/6 23:37:19 - TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案
一、背景需求分析 在工业产业园、化工园或生产制造园区中,周界防范意义重大,对园区的安全起到重要的作用。常规的安防方式是采用人员巡查,人力投入成本大而且效率低。周界一旦被破坏或入侵,会影响园区人员和资产安全,…...
2024/5/6 7:24:07 - VB.net WebBrowser网页元素抓取分析方法
在用WebBrowser编程实现网页操作自动化时,常要分析网页Html,例如网页在加载数据时,常会显示“系统处理中,请稍候..”,我们需要在数据加载完成后才能继续下一步操作,如何抓取这个信息的网页html元素变化&…...
2024/5/7 0:32:52 - 【Objective-C】Objective-C汇总
方法定义 参考:https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...
2024/5/6 6:01:13 - 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】
👨💻博客主页:花无缺 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】🌏题目描述🌏输入格…...
2024/5/6 7:24:06 - 【ES6.0】- 扩展运算符(...)
【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数࿰…...
2024/5/7 1:54:46 - 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?
文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕,各大品牌纷纷晒出优异的成绩单,摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称,在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁,多个平台数据都表现出极度异常…...
2024/5/6 20:04:22 - Go语言常用命令详解(二)
文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令,这些命令可以帮助您在Go开发中进行编译、测试、运行和…...
2024/5/7 0:32:51 - 用欧拉路径判断图同构推出reverse合法性:1116T4
http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b,我们在 a i a_i ai 和 a i 1 a_{i1} ai1 之间连边, b b b 同理,则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然࿰…...
2024/5/6 7:24:04 - 【NGINX--1】基础知识
1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息,并安装一些有助于配置官方 NGINX 软件包仓库的软件包: apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...
2024/5/6 7:24:04 - Hive默认分割符、存储格式与数据压缩
目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限(ROW FORMAT)配置标准HQL为: ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...
2024/5/6 19:38:16 - 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法
文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中,传感器和控制器产生大量周…...
2024/5/6 7:24:03 - --max-old-space-size=8192报错
vue项目运行时,如果经常运行慢,崩溃停止服务,报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中,通过JavaScript使用内存时只能使用部分内存(64位系统&…...
2024/5/7 0:32:49 - 基于深度学习的恶意软件检测
恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞,例如可以被劫持的合法软件(例如浏览器或 Web 应用程序插件)中的错误。 恶意软件渗透可能会造成灾难性的后果,包括数据被盗、勒索或网…...
2024/5/6 21:25:34 - JS原型对象prototype
让我简单的为大家介绍一下原型对象prototype吧! 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象,所以我们也称为原型对象…...
2024/5/6 7:24:02 - C++中只能有一个实例的单例类
C中只能有一个实例的单例类 前面讨论的 President 类很不错,但存在一个缺陷:无法禁止通过实例化多个对象来创建多名总统: President One, Two, Three; 由于复制构造函数是私有的,其中每个对象都是不可复制的,但您的目…...
2024/5/6 7:24:01 - python django 小程序图书借阅源码
开发工具: PyCharm,mysql5.7,微信开发者工具 技术说明: python django html 小程序 功能介绍: 用户端: 登录注册(含授权登录) 首页显示搜索图书,轮播图࿰…...
2024/5/7 0:32:47 - 电子学会C/C++编程等级考试2022年03月(一级)真题解析
C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...
2024/5/6 16:50:57 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57