作者:liuxiaopeng
链接:https://www.cnblogs.com/paddix/p/8365558.html
前两章我们分享了Spring boot对Restful 的支持,不过Restful的接口通常仅仅返回数据。而做web开发的时候,我们往往会有很多静态资源,如html、图片、css等。那如何向前端返回静态资源呢?以前做过web开发的同学应该知道,我们以前创建的web工程下面会有一个webapp的目录,我们只要把静态资源放在该目录下就可以直接访问。但是,基于Spring boot的工程并没有这个目录,那我们应该怎么处理?
一、最笨的方式
我们首先来分享一种最笨的办法,就是将静态资源通过流直接返回给前端,我们在maven工程的resources的根目录下建立一个html的目录,然后我们把html文件放在该目录下,并且规定任何访问路径以/static/开头的即访问该目录下的静态资源,其实现如下:
@Controller
public class StaticResourceController {
@RequestMapping("/static/**")
public void getHtml(HttpServletRequest request, HttpServletResponse response) {
String uri=request.getRequestURI();
String[] arr=uri.split("static/");
String resourceName= "index.html";
if (arr.length > 1) {
resourceName=arr[1];
}
String url=StaticResourceController.class.getResource("/").getPath() + "html/" + resourceName;
try {
FileReader reader= new FileReader(new File(url));
BufferedReader br= new BufferedReader(reader);
StringBuilder sb= new StringBuilder();
String line=br.readLine();
while (line != null) {
sb.append(line);
line=br.readLine();
}
response.getOutputStream().write(sb.toString().getBytes());
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
}
}
}
其实现过程很简单,就是先从路径中分离出来资源uri,然后从static目录下读取文件,并输出到前端。因为只做简单演示,所以这里只处理了文本类型的文件,图片文件可以做类似的处理。当然,我们在实际中肯定不会这么做,Spring boot也肯定有更好的解决办法。不过这个办法虽然有点笨,但确是最本质的东西,无论框架如何方便的帮我们处理了这类问题,但是抛开框架,我们依然要能够熟练的写出一个web项目,只有知道其实现原理,你才会在遇到问题时能得心应手。现在我们再来看看Spring boot对静态资源的支持。
二、Spring boot默认静态资源访问方式
Spring boot默认对/**的访问可以直接访问四个目录下的文件:
classpath:/public/
classpath:/resources/
classpath:/static/
classpath:/META-INFO/resouces/
我们现在就在资源文件resources目录下建立如下四个目录:
注意蓝色条下的资源文件夹resources与类路径下的文件夹classpath:/resources是不同的,蓝色条下的resources代表的是该目录下的文件为资源文件,在打包的时候会将该目录下的文件全部打包的类路径下,这个名称是可以改的,在pom.xml指定资源目录即可:
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
而类路径下的resources是spring boot默认的静态资源文件夹之一,和public、static以及MEAT-INFO/resources的功能相同。现在我们重启Spring boot就可以通过
http://localhost:8080/1.html
http://localhost:8080/2.html
http://localhost:8080/3.html
http://localhost:8080/4.html
四个URL访问到四个目录下的静态资源了。
三、自定义静态资源目录
通过第二节内容我们已经知道了Spring boot默认可以访问的静态资源的目录,但是大家肯定会想,这个目录是固定的吗?我们可不可以自己定义静态资源目录?答案是肯定的,我们现在就来自定义一个静态资源目录,我们定义一个images的目录来存放图片,所有/image/**的路径都会访问images目录下的资源:
@Configuration
public class ImageMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/image/**")
.addResourceLocations("classpath:/images/");
}
}
这段代码应该比较简单,@Configuration标识一个配置类,这个在前面的文章中提到过多次。WebMvcConfigurerAdapter是Spring提供的一个配置mvc的适配器,里面有很多配置的方法,addResourceHandlers就是专门处理静态资源的方法,其他方法后续我们还会讲到。现在我们在验证上面的配置是否有效。我在images目录下放了一张spring.jpg的图片,现在我们通过http://localhost:8080/image/spring.jpg来访问图片:
其实除了上面的办法还有一种更简单的办法,就是直接在application.yml中配置即可:
spring:
mvc:
static-path-pattern: /image/**
resources:
static-locations: classpath:/images/
static-path-pattern:访问模式,默认为/**,多个可以逗号分隔
static-locations:资源目录,多个目录逗号分隔,默认资源目录为classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
注意,这个配置会覆盖Spring boot默认的静态资源目录,例如如果按示例中配置,则无法再访问static、public、resources等目录下的资源了。
四、总结
本文主要给大家分享了Spring boot 对静态资源的处理方式,Spring boot 默认可以访问classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/四个目录下的静态资源,我们也可以根据自己的需要进行个性化配置。最后,需要说明一点的是,如果这四个目录中存在相同名称的资源,那会优先返回哪个目录下的资源呢?大家通过static-locations的默认值顺序应该能猜到,默认情况下,Spring boot会优先返回/META-INF/resources下的资源。当然,因为我们可以自定义static-locations的值,所以这个优先顺序也是可以调整的。
在之前的4篇的内容里,我们较为详细的介绍了路由以及控制器还有视图之间的关系。也就是说,系统如何从用户的HTTP请求解析到控制器里,然后在控制器里处理数据,并返回给视图,在视图中显示出来。这一篇我将为大家介绍基础的最后一部分,布局页和静态资源引入。
在控制器和视图那一篇,我们了解到_ViewStart 里设置了一个Layout属性的值,这个值正是用来设置布局页的。所谓的布局页,就是视图的公用代码。在实际开发中,布局页通常存放我们为整个系统定义的页面框架,视图里写每个视图的页面。
回顾一下,默认的_ViewStart里的内容是:
@{
Layout="_Layout";
}
默认的布局页指定的是名为_Layout的布局页,在本系列第三篇中,我们得知这个视图应当在Shared文件夹下,那我们进去看一下这个视图有什么内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - MvcWeb</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MvcWeb</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
? 2020 - MvcWeb - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>
这是默认的布局页内容,看着挺多的,但是除了一些html代码,里面还有一些关键的地方需要注意。
RenderSection 分部渲染,在页面中创建一个标记,表示这个页面块将在子视图(或者是路由的实际渲染视图)中添加内容。
来,我们看一下微软官方给的注释:
In layout pages, renders the content of the section named name.
意思就是在布局页中,渲染名称为name的分部内容。
新创建一个分布页,名称为_Layout1:
<html>
<head>
<title>Render 测试</title>
</head>
<body>
@RenderSection("SectionDemo")
</body>
</html>
这个布局页里什么都没有,只有一个RenderSection。现在我们新建一个控制器:
using Microsoft.AspNetCore.Mvc;
namespace MvcWeb.Controllers
{
public class RenderTestController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
创建对应的视图:
Views / RenderTest/Index.cshtml
先设置布局页为_Layout1:
@{
Layout="_Layout1";
}
先试试启动应用,访问:
http://localhost:5006/RenderTest/Index
正常情况下,你应该能看到这个页面:
仔细看一下信息,意思是在 RenderTest/Index.cshtml 视图中没有找到 SectionDemo 的分部内容。
那么,如何在视图中设置分部内容呢?
@{
Layout="_Layout1";
}
@section SectionDemo{
<h1>你好</h1>
}
使用 @section <Section 名称> 后面跟一对大括号,在大括号中间的内容就是这个section(分部)的内容。
重启应用,然后刷新页面,你能看到这样的页面:
如果不做特殊要求的话,定义在布局页中的分部块,视图必须实现。当然,RenderSection还有一个参数,可以用来设置分部不是必须的:
public HtmlString RenderSection(string name, bool required);
先看下微软给的官方注释:
In a Razor layout page, renders the portion of a content page that is not within a named section.
简单讲,如果在布局页中设置了@RenderBody,那么在使用了这个布局页的视图里所有没被分部块包裹的代码都会渲染到布局页中声明了@RenderBody的地方。
修改_Layout1.cshtml:
<html>
<head>
<title>Render 测试</title>
</head>
<body>
<h1>RenderBody 测试 -之前</h1>
@RenderBody()
<h1>RenderBody 测试 -之后</h1>
</body>
</html>
修改RenderTest/Index.cshtml:
@{
Layout="_Layout1";
}
RenderBody测试
<h1>我是视图的内容!</h1>
重启应用,刷新刚刚访问的页面:
可以看出,RenderBody渲染的位置。
通常情况下,静态资源的引入与HTML引用js和css等资源是一致的,但是对于我们在编写系统时自己创建的脚本和样式表,asp.net core提供了不同的处理方式。那就是服务器端压缩功能。
asp.net core 3.0 的mvc 默认项目是不启动这个功能的,需要我们额外的开启支持。
先引入 BuildBundleMinifier
cd MvcWeb # 切换目录到MvcWeb项目下
dotnet add package BuildBundleMinifier
创建 bundleconfig.json
[
{
"outputFileName": "wwwroot/css/site.min.css",
"inputFiles": [
"wwwroot/css/site.css"
]
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"wwwroot/js/site.js"
],
"minify": {
"enabled": true,
"renameLocals": true
},
"sourceMap": false
}
]
每个节点允许设置项:
正常情况下在布局页中,把压缩后的文件路径引入即可。不过在开发中,通常按照以下方式引用:
<environment exclude="Development">
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>
<environment include="Development">
<link rel="stylesheet" href="~/css/site.css" />
</environment>
注: asp-append-version 表示在引用路径追加一个版本号,这是针对html静态资源缓存的问题的一个解决方案,这一步是由程序决定的。
environment表示环境,现在大家知道这个写法就行,在接下来的篇幅会讲。
我们知道到目前为止,我们的静态资源都是在wwwroot目录下。那么我们是否可以修改或者添加别的目录作为静态资源目录呢?
在Startup.cs文件内的Configure方法下有这样一行代码:
app.UseStaticFiles();
这行代码的意思就是启用静态文件,程序自动从 wwwroot寻找资源。那么,我们就可以从这个方法入手,设置我们自己的静态资源:
public static IApplicationBuilder UseStaticFiles(this IApplicationBuilder app, StaticFileOptions options);
我们找到了这个方法的另一个重载版本,里面有一个参数类:
public class StaticFileOptions : SharedOptionsBase
{
public StaticFileOptions();
public StaticFileOptions(SharedOptions sharedOptions);
public IContentTypeProvider ContentTypeProvider { get; set; }
public string DefaultContentType { get; set; }
public HttpsCompressionMode HttpsCompression { get; set; }
public Action<StaticFileResponseContext> OnPrepareResponse { get; set; }
public bool ServeUnknownFileTypes { get; set; }
}
并没有发现我们想要的,先别慌,它还有个父类。我们再去它的父类里看看:
public abstract class SharedOptionsBase
{
protected SharedOptionsBase(SharedOptions sharedOptions);
public IFileProvider FileProvider { get; set; }
public PathString RequestPath { get; set; }
protected SharedOptions SharedOptions { get; }
}
这下就比较明了了,需要我们提供一个文件提供器,那么我们来找一个合适的IFileProvider实现类吧:
public class PhysicalFileProvider : IFileProvider, IDisposable
这个类可以满足我们的要求,它位于命名空间:
namespace Microsoft.Extensions.FileProviders
那么,添加一组我们自己的配置吧:
using Microsoft.Extensions.FileProviders;
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// 省略其他代码,仅添加以下代码
app.UseStaticFiles(new StaticFileOptions
{
FileProvider=new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),"OtherStatic")),
});
}
在项目的根目录创建名为OtherStatic的文件夹,然后在里面创建个文件夹,例如: files,并在这个文件夹里随便添加一个文件。
然后启动应用访问:
http://localhost:5006/files/<你添加的文件(包括后缀名)>
然后能在浏览器中看到这个文件被正确响应。
当然,这里存在一个问题,如果在 OtherStatic中的文件在wwwroot也有相同目录结构的文件存在,这样访问就会出现问题。这时候,可以为我们新加的这个配置设置一个请求前缀:
app.UseStaticFiles(new StaticFileOptions
{
FileProvider=new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),"OtherStatic")),
RequestPath="/other"
});
重启程序,然后访问:
http://localhost:5006/other/files/<你添加的文件(包括后缀名)>
然后就能看到刚才响应的文件,重新访问之前的路径,发现浏览器提示404。
在这一篇,我们讲解了布局页的内容,静态资源的压缩绑定以及添加一个新的静态资源目录。通过这几篇内容,让我们对asp.net core mvc有了一个基本的认知。下一篇,我们将重新创建一个项目,并结合之前的内容,以实战为背景,带领大家完成一个功能完备的web系统。
求关注,求点赞,求转发~~有啥可以评论哟
jango并不象其他WEB语言,可以在前端页面指定图片,CSS等静态资源的路径就能直接访问。
要使用静态资源,还需要一些必要的设置。
1,在项目app目录中新建一个static目录
static目录再创建一个css目录,放一个style.css文件
在static目录放一个 1.png 图片
2,配置项目的settings.py文件
STATIC_URL='/static/'
STATICFILES_DIRS=(
os.path.join(BASE_DIR, 'static').replace('\', '/'),
)
3,配置urls.py文件
加入如下url:
url(r'^static/(?P<path>.*)', serve, {'document_root': '/myweb/web/static'}),
配置完后就可以在前端页面使用静态资源了,
比如引用css文件:<link rel="stylesheet" href="./static/css/style.css">
比如引用图片:<img src="static/1.png">
*请认真填写需求信息,我们会在24小时内与您取得联系。