springBoot自动装配原理探究springBoot配置类Thymeleaf模板引擎

news2024/11/15 10:53:18

微服务

微服务是一种架构风格,由于单体架构不利于团队协作完成并且代码量较大,后期维护成本较高,逐渐有了微服务架构。微服务是将一个项目拆分成不同的服务,各个服务之间相互独立互不影响,互相通过轻量级机制通信比如http通信。各个服务模块可以看成是一个单独的项目,可以由不同的编程语言,不同的数据存储技术进行开发,从而有效的实现“松耦合”。**微服务的目的就在于拆分应用、模块独立开发和部署。**相比于单体架构,微服务最大的优势就是实现了拆分应用、统一管理。

什么是springBoot

SpringBoot是一款基于Spring的快速开发框架,使用springBoot可以快速开发spring应用

springBoot为了简化使用ssm的大量复杂的配置文件,因此它内置了大量的市面主流组件,而任何一个springBoot内置的组件都对应有一个配置类。比如模板引擎thymeleaf对应的配置类ThymeleafProperties。并且我们依然可以在此基础上继续扩展或者进行其他配置,可以通过application.yml或者application.properties进行配置

SpringBoot内部集成了TomCat,不需要额外的配置,启动主程序即可运行

搭建SpringBoot

Spring内置了大量的第三方组件供我们使用,我们不再需要单独的去导入这些组件的依赖,这些组件都位于spring-boot-starter-xxx中可以理解为是一个启动器。并且spring也提供了这些组件的各个参数,来实现自定义组件开发,spring会根据我们的配置文件以及所导入的启动器来进行自动装配,自动装配是spring的核心所在
自动装配基于启动器,启动器配置依赖在Pom.xml文件中,比如

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
</dependency>

将需要使用的依赖项配置即可,官网示例

在这里插入图片描述

下面是spring提供的主程序,也就是整个项目的入口。因为spring已经内置了一些服务器组件比如tomcat,我们从主程序启动就会由spring来完成服务器的项目部署以及运行。

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

spring自动装配原理

@SpringBootApplication注解,其中包含

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 上述四个是定义注解需要  核心注解是下面三个
@SpringBootConfiguration  // SpringBoot配置
@EnableAutoConfiguration  //  自动配置
@ComponentScan(   // 扫描包
  excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
  ), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
  )}
)

可以看到@SpringBootApplication是一个符合注解,也就是说如果直接定义@SprngBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解也可以启动项目

@SpringBootConfigUration的内部其实是一个@Configuration注解,其作用就是将该注解所修饰的当前类作为配置类并且交给Spring容器托管,那么spring在扫描配置时便会扫描到该类,配置即可生效

@ComponentScan扫描包,相当于在spring的application-context.xml文件中去配置了conext:component-scan,如果不配置路径就会扫描当前所在包及其子包中的所有注解。目的就是让@Controller、@Service等注解生效

@EnableAutoConfiguration是实现自动装配的关键,它包含两个注解分别是@Import和@AutoConfigurationPackage
@Import引入了一个类AutoConfigurationImportSelector.class
该类是完成自动装配的重点:

  1. 先看该类下的selectImports方法,
public String[] selectImports(AnnotationMetadata annotationMetadata) {
  // 判断注解的数据是否存在
  if (!this.isEnabled(annotationMetadata)) {
    // 没有数据九返回  No-IMPORTS一个空的String数组
    return NO_IMPORTS;
  } else {
    // 否则将注解数据封装为自动配置的实体对象
    AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
    return 
// 获取注解中的全部数据并转换成String数组  返回
StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
  }
}
  1. 点开封装注解数据的方法getAutoConfigurationEntry(annotationMetadata)

在这里插入图片描述

  1. getCandidateConfigurations方法:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
  ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
  Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
  return configurations;
}

可以发现当中给出了错误提示:根据@EnableConfiguration的全限定名去META-INF/spring.factories文件中获取我们需要导入的类,
@EnableConfiguration全限定名为:

org.springframework.boot.autoconfigure.EnableAutoConfiguration

最终会找到文件spring.factories,也就是大量需要自动装配的类

在这里插入图片描述
@AutoConfigurationPackage就是将主程序所在的包作为自动配置的包,spring默认会扫描本包及子包下的注解

@ConfigurationProperties注解可以将该配置类中的每一个属性值映射到yml文件当中进行绑定 该注解提供prefix字段用于指定yml同名的属性,我们可以使用该注解指定配置类

松散绑定:yml中的属性字段可以使用-进行风格,则其对应配置类中的属性就是连接-前后的字段并改为驼峰命名的属性。
例如:yml文件中:student-count对应student类中的studentCount属性,与mybatis中的驼峰命名映射类似

yml语法:

# 以key-value形式存储  key不能重复
server:
port: 8081
# 对象 行内写法
student: { name: yuqu,age: 13 }
# 对象
student2:
name: yuqu
age: 13
# 数组
students:
- 张三
- 李四
- 王五

进行配置时,你可以使用@Value注解直接为某字段赋值,也可以使用properties文件进行赋值,但是两者都没有yml更加灵活

JSR303校验

@Validatad数据校验注解,放在配置类的声明上,放置后则可以在该类下的字段上进行其他具体的校验配置,比如邮箱@Email()则该字段必须符合邮箱格式,否则报错,记得要添加JSR303校验的启动器,就是依赖

<!--        JSR303数据校验-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
@Validated
public class Person {
  @Email()
  private String name;

常用HSR303注解

空检查
  @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           验证 DateCalendar 对象是否在当前时间之前  
  @Future     	验证 DateCalendar 对象是否在当前时间之后  
  @Pattern    	验证 String 对象是否符合正则表达式的规则

  数值检查,建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng"",Integernull
  @Min            验证 NumberString 对象是否大等于指定的值  
  @Max            验证 NumberString 对象是否小等于指定的值  
  @DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
  @DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
  @Digits     验证 NumberString 的构成是否合法  
  @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=)

SpringBoot核心:自动配置

导入静态资源

  1. 可以使用下面方式处理静态资源

    1. webjars
    2. public
    3. static
    4. /* *
    5. resource
  2. 这些是spring规定的默认扫描静态资源的位置,优先级为

    static > public > resource

在这里插入图片描述

定制首页:

默认情况下spring会在静态资源中寻找名叫index.html的页面作为首页
在templates下面的所有页面只能通过controller进行跳转,但需要模板引擎的支持

thymeleaf模板引擎

导入依赖

<!--     thymeleaf模板引擎   -->
<dependency>
  <groupId>org.thymeleaf</groupId>
  <artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
  <groupId>org.thymeleaf.extras</groupId>
  <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>

之前在使用springmvc开发时,依然是使用jsp视图与后端进行数据交互。但是spring并不推崇使用jsp,因为jsp的前后端耦合性过高。spring推荐使用html,只负责前端视图的展示,而数据交互就使用模板引擎比如上面提到的thymeleaf。简单来说就是之前我们使用servlet+jsp 换成了现在的servlet+thymeleaf+html

  1. 所有的模板引擎卸载templates包下
  2. 必须是以.html后缀结尾
  3. 引入命名空间:<html lang="en" xmlns:th="http://www.thymeleaf.org">

示例:

@Controller
// 自动交由thymeleaf解析,并跳转至templates下的hello页面
// 注意如果没有配置thymeleaf依赖是无法跳转的
public class controller {
  @RequestMapping(value = "/hello")
  public String hello(){
    return "hello";
  }
}

由此,我们不需要再去配置springmvc的视图解析器并配置指定包下的.jsp文件后缀,全部交由模板引擎thymeleaf可以正常完成跳转

一些常用的thymeleaf语法:

<!--th:text 设置当前元素的文本内容,常用,优先级不高-->
<p th:text="${thText}" />
<!--th:value 设置当前元素的value值,常用,优先级仅比th:text高-->
<input type="text" th:value="${thValue}" />
<!-- 遍历数组 -->
<div>
    <p th:each="user: ${users}" th:text="${user}"></p>
</div>
<!--th:if 条件判断,类似的有th:switch,th:case,优先级仅次于th:each, 其中#strings是变量表达式的内置方法-->
<p th:text="${thIf}" th:if="${not #strings.isEmpty(thIf)}"></p>
<!-- 使用format函数指定格式 -->
th:text="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}"
<!-- restFul风格传参 -->
th:href="@{/delete/}+${emp.getId()}"
<!--  js函数传参  -->
th:οnclick="update([[${emp.getId()}]])"

fragment抽取公共页面

在需要抽离的html中的最大标签定义th:fragment="sidebar",名称可以自定义,在需要引入的地方插入th:insert="~{dashboard::sidebar}",对应dashboard就是页面名称,后边为自定义字段

自动配置SpringMVC

自动转换器:前端提交的数据,经自动转换器自动封装为后台接收的对象
视图解析器、静态资源支持等等这些是SpringBoot已经内置好的springmvc的特性,我们依然可以通过手动去继续扩展其他配置比如拦截器、格式化器等等

自定义配置类,实现WebMvcConfigurer接口,利用@Configuration注解修饰,而且不能标注@EnableWebMvc。以自定义视图解析器DispatcherServlet为例:

@Configuration
public class MyConfig implements WebMvcConfigurer {
  public static class MyViewResolver implements ViewResolver{
    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception {
      return null;
    }
  }
  @Bean
  public ViewResolver myViewResolver(){
    return new MyViewResolver();
  }
}

排错关于静态资源加载

针对thymeleaf加载静态资源时出现No mapping for GET /css/bootstrap.min.css等一系列资源找不到的问题,原因是利用@EnableWebMvc注解修饰了配置类,导致springBoot无法根据默认的静态资源位置进行扫描所以找不到。解决方法两种:

  1. 取出@EnableWebMvc注解
  2. 实现WebMvcConfigurer接口之后重新定义CLASSPATH_RESOURCE_LOCATIONS静态资源路径和资源处理器,如下
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
  "classpath:/META-INF/resources/", "classpath:/resources/",
  "classpath:/static/", "classpath:/public/" };

// 资源处理
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
  if (!registry.hasMappingForPattern("/webjars/**")) {
    registry.addResourceHandler("/webjars/**").addResourceLocations(
      "classpath:/META-INF/resources/webjars/");
  }
  if (!registry.hasMappingForPattern("/**")) {
    registry.addResourceHandler("/**").addResourceLocations(
      CLASSPATH_RESOURCE_LOCATIONS);
  }

国际化消息转换LocaleResolver(区域设置解析)

配置i18n文件:在这里插入图片描述在这里插入图片描述

分别对应英文和中文,配置完成后修改前端界面的具体字段,以“请 登 录”为例:

<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.login}">Please sign in</h1>

也可以继续进行扩展,利用a标签实现点击切换中英文对照,如下:

<a class="btn btn-sm" th:href="@{/index.html(lang='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(lang='en_US')}">English</a>

配置地区分解组件,并将其注入到配置类中托管给spring

// 地区分解  视图中英文调换
public class MyLocaleResolve implements LocaleResolver {
  // 解析请求
  @Override
  public Locale resolveLocale(HttpServletRequest request) {
    // 获取请求的语言参数
    String lang = request.getParameter("lang");
    System.out.println("获取到视图传回的lang="+lang);
    // 默认语言参数
    Locale locale = Locale.getDefault();
    if (!StringUtils.isEmpty(lang)){
      // 不为空  使用请求的语言
      String[] s = lang.split("_");
      locale = new Locale(s[0], s[1]);
    }
    return locale;
  }
  @Override
  public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
  }
}

注入@Configuration配置类中

// 自定义地区分解组件注入  生效
@Bean
public LocaleResolver localeResolver(){
  return new MyLocaleResolve();
}

yml配置:

spring:
  # 关闭thymeleaf缓存
  thymeleaf:
    cache: false
    # 配置中英转换
  messages:
    basename: i18n.login

拦截器

设置未登录用户权限,拦截请求

  1. 自定义登录拦截器 LoginHandlerInterceptor实现HandlerInterceptor接口并重写preHandle方法,根据用户是否登录和请求url进行判断,
// 登录拦截器
public class LoginHandlerInterceptor implements HandlerInterceptor {
  // 配置拦截器 请求拦截
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // 查看当前用户是否已经登录
    Object currentUser = request.getSession().getAttribute("currentUser");
    if (currentUser==null){
      request.setAttribute("message","没有权限,请先登录!");
      // 没有登录返回登陆界面
 request.getRequestDispatcher("/index.html").forward(request,response);
      return false;
    }else {
      return true;
    }
  }
}
  1. 向配置类中注入自定义的拦截器
// 注入自定义拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
  registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login","/css/*","/js/*","/img/*");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/376573.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(转载)STM32与LAN9252构建EtherCAT从站

目录 &#xff08;一&#xff09;&#xff1a;项目简介 EtherCAT及项目简述 LAN9252工作模式 整体开发流程 移植要处理的问题 代码层面的工作 开发中使用的工具 &#xff08;二&#xff09;&#xff1a;SSC的使用 SSC简介和下载 SSC构建协议栈文件和XML &#xff08…

爬虫数据解析-正则表达式

数据解析-正则表达式 正则表达式 正则编写规则简介 字符含义.匹配除换行符以外的任意字符|A|B表示&#xff1a;匹配正则表达式条件A或B^匹配字符串的开始(在集合[]里表示"非"&#xff09;的意思$匹配字符串的结束{n}重复n次{,n}重复小于n次{n,}重复n次或更多次{n,…

2023软件测试金三银四常见的软件测试面试题-【抓包和网络协议篇】

八、抓包与网络协议 8.1 抓包工具怎么用 我原来的公司对于抓包这块&#xff0c;在App的测试用得比较多。我们会使用fiddler抓取数据检查结果&#xff0c;定位问题&#xff0c;测试安全&#xff0c;制造弱网环境; 如&#xff1a;抓取数据通过查看请求数据&#xff0c;请求行&…

经验 // 指标异常了怎么办?

本文参考了数据万花筒的文章&#xff0c;结合我自己工作经验。希望给大家一些帮助。 指标异常排查&#xff0c;是数据分析师的工作重点之一&#xff0c;是各行各业数据分析师都绕不开的话题。 本文试图回答&#xff1a; 1、指标波动的影响因素有哪些&#xff1f; 2、如何快速…

Web3中文|泰勒·斯威夫特演唱会票务闹乌龙,NFT票务急需普及

2022年底&#xff0c;美国艺人Taylor Swift&#xff08;泰勒斯威夫特&#xff09;的2023年巡回演唱会Eras Tour门票开始出票。作为当今世界最受欢迎的流行歌手之一&#xff0c;四年多没举办大型巡演无疑积攒了大量的粉丝需求。但是在2022年11月15日开放预售的当天&#xff0c;售…

数据驱动下的物种保护,拯救生命的“特效药”

如果给出这样      一张猎豹的图片      我们能否通过图中有限的信息      判断它的年龄、健康状况      以及所属族群?      如果你是一名研究动物的专家,你可能会从其花纹和斑点中获取一定量的信息,但对于大多数人以及一线的动物保护者来说,它可能只是一…

imx6ull——I2C驱动

I2C基本介绍 SCL 为高电平&#xff0c;SDA 出现下降沿:起始位 SCL 位高电平&#xff0c;SDA出现上升沿:停止位 主机——从机地址&#xff08;ack&#xff09;——寄存器地址&#xff08;ack&#xff09;——数据&#xff08;ack&#xff09; 重点&#xff1a;先是写&#xff0c…

context.Context

context.Context前言一、为什么要context二、context有什么用三、基本数据结构3.1、context包的整体工作机制3.2 基本接口和结构体3.3 API函数3.4 辅助函数3.5 context用法3.6 使用 context 传递数据的争议总结参考资料前言 context是go语言的一个并发包&#xff0c;一个标准库…

平台总线开发(id和设备树匹配)

目录 一、ID匹配之框架代码 二、ID匹配之led驱动​​​​​​​ 三、设备树匹配 四、设备树匹配之led驱动 五、一个编写驱动用的宏 一、ID匹配之框架代码 id匹配&#xff08;可想象成八字匹配&#xff09;&#xff1a;一个驱动可以对应多个设备 ------优先级次低 注意事项…

河南农信社数字化转型实践方案

农信机构立足地方“三农”&#xff0c;普遍规模较小&#xff0c;高地域集中度在县域和农村地区&#xff0c;容易受到地方农村经济脆弱性的影响。 农信机构由于信贷项目要求多&#xff0c;单笔贷款业务批复的额度相对较小&#xff0c;在信用档案登记环节&#xff0c;造成业务量…

SQL Server主流版本生命周期管理

SQL Server 生命周期 每个版本的 SQL Server 都有至少 10 年的支持期限&#xff0c;其中包括五年的主要支持和五年的扩展支持&#xff1a; “主要支持” 包括功能、性能、可伸缩性和安全更新。“扩展支持” 仅包含安全更新。 “终止支持” &#xff08;有时也称为生命周期结束…

udp套接字编程(超详细带你逐步实现)

我自己在学习UDP服务器的时候&#xff0c;有着太多的不解&#xff0c;我不明白一个udp服务器是如何设计出来的。我在网上找了很多的资料&#xff0c;不过绝大多数都是把代码往哪里一放&#xff0c;具体的设计流程完全不提&#xff0c;这让我看了之后一头雾水。或许对于刚刚开始…

scikit-learn实现近邻算法分类的示例

scikit-learn库 scikit-learn已经封装好很多数据挖掘的算法 现介绍数据挖掘框架的搭建方法 转换器&#xff08;Transformer&#xff09;用于数据预处理&#xff0c;数据转换流水线&#xff08;Pipeline&#xff09;组合数据挖掘流程&#xff0c;方便再次使用&#xff08;封装…

SVN配置使用(钩子配置、updata忽略指定文件)

参考链接&#xff1a; svn(svnsync)实时同步备份及问题解答 SVN常用命令之update SVN钩子就是一个脚本&#xff0c;在SVN更新前、后、或者变化前后等等状态&#xff0c;触发的脚本。据此可以有多种用途&#xff0c;如&#xff1a;1、在版本提交前要求必须对更新进行说明&#…

20分钟6个示例4个动图教你学会Async Hooks

序幕 async_hooks模块提供了一个全新的功能世界,但作为 Node.js 爱好者,我最感兴趣的是,它可以让您轻松了解我们在应用程序中经常执行的一些任务的幕后情况。 在本文中,我将尝试借助async_hooks模块来演示和解释一个典型的异步资源的生命周期。 Async Hooks API 简介 as…

【源码解析】SpringBoot自动装配的实现原理

什么是SpringBoot的自动装配 SpringBoot在启动的时候会扫描外部jar包中的META-INF/spring.factories文件&#xff0c;将文件中配置的类信息按照条件装配到Spring容器中。 实现原理 核心注解SpringBootApplication Target({ElementType.TYPE}) Retention(RetentionPolicy.R…

时间序列分析 | BiLSTM双向长短期记忆神经网络时间序列预测(Matlab完整程序)

时间序列分析 | BiLSTM双向长短期记忆神经网络时间序列预测(Matlab完整程序) 目录 时间序列分析 | BiLSTM双向长短期记忆神经网络时间序列预测(Matlab完整程序)预测结果评价指标基本介绍完整程序参考资料预测结果 评价指标 训练集数据的R2为:0.99302 测试集数据的R2为&…

企业数字化(技术中台、数据中台、工业互联网平台)建设方案

【版权声明】本资料来源网络&#xff0c;知识分享&#xff0c;仅供个人学习&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间删除&#xff01;完整资料领取见文末&#xff0c;部分资料内容&#xff1a; 1.1 技术架构 1.1.1 技术架构总…

pandas提取excel数据形成三元组,采用neo4j数据库构建小型知识图谱

前言 代码来自github项目 neo4j-python-pandas-py2neo-v3&#xff0c;项目作者为Skyelbin。我记录一下运行该项目的一些过程文字以及遇到的问题和解决办法。 一、提取excel中的数据转换为DataFrame三元组格式 from dataToNeo4jClass.DataToNeo4jClass import DataToNeo4j imp…

Unity WebGL打包后运行

打包后出现以下&#xff1a;工程中没有StreamingAssets文件夹的&#xff0c;则打包后不会有下图StreamingAssets的文件夹 这3个文件夹都是项目资源&#xff0c;只有index.html才是打开Web运行的页面 序列 主流浏览器 WebGL支持 1 Microsoft Edge Edge16或更高版本 2 火狐…