写点什么

网站的静态资源怎么获取?

  • 2024-04-19
    福建
  • 本文字数:4525 字

    阅读完需:约 15 分钟

功能需求如下:


  1. 现有一个后端应用,默认访问方式如下:http://47.120.49.119:8080/#/

  2. 用电脑、平板、手机等设备都可以访问,且不同的设备样式要适配,前端做了两套,但是访问接口都是同一个;

  3. 由于没有使用 cdn,界面渲染的时候需要用到的字体库、图标库和一些图片也放在了后端应用;


光文字讲需求可能不太直观,我放一些图片就好理解了,如下:


使用电脑访问http://47.120.49.119:8080/#/出现的界面



使用手机或平板访问http://47.120.49.119:8080/#/出现的界面



可以看到这两个的样式不一样,组件也不一样,但是接口都是同一个。


前端的资源如下



文件有 html、js、css,还有一些特殊的文件如字体,文件类型还是比较丰富的,且这样的资源有两份,一份是电脑端,一份是移动端。由于没有使用 cdn,我们需要通过后端服务来访问这些资源。那么说到这里不知道大家有没有理解这个需求呢?其实简单理解就是 SpringBoot 的接口访问静态资源,下面就开始讲一下我是如何实现这个功能的。


一、功能实现


1. 从访问一个 index.html 开始


(1)创建一个 SpringBoot 项目


这个我就不啰嗦了,使用 ide 或者https://start.spring.io/网站创建一个即可。


(2)引入 SpringBoot 模板引擎— Thymeleaf


pom.xml 引入

<!-- thymeleaf --><dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>
复制代码


(3)在 resources 目录下创建一个 static 文件夹,在 static 文件夹创建一个 index.html



(4)application.properties 添加如下配置

spring.thymeleaf.prefix=classpath:/static/spring.thymeleaf.suffix=.htmlspring.thymeleaf.mode=HTML
复制代码


(5)写一个 IndexController.java

package com.summo.file.controller;
import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;
@Controllerpublic class IndexController {
@GetMapping("/") public String index() { return "index"; }}
复制代码


(6)访问一下 index.html



这个还是比较简单的,我已经成功了,大家成功了吗?如果发现返回的不是 HTML 而是字符串,检查一下 IndexController 的注解,是 @Controller 而不是 @RestController,方法上也不要加 @ResponseBody。


2. 判断当前的请求来自于电脑还是手机


(1)判断逻辑分析


这个听起来很难,其实很简单,前端在访问后端接口的时候,会携带一个USER-AGENT的请求头,通过这个USER-AGENT请求头就可以区分访问来源,判断逻辑代码如下:

/**   * 校验是否手机端   *   * @param request   * @return   */public static boolean isFromMobile(HttpServletRequest request) {  //1. 获得请求UA  String userAgent = request.getHeader("USER-AGENT").toLowerCase();  //2.声明手机和平板的UA的正则表达式  // \b 是单词边界(连着的两个(字母字符 与 非字母字符) 之间的逻辑上的间隔),  // 字符串在编译时会被转码一次,所以是 "\\b"  // \B 是单词内部逻辑间隔(连着的两个字母字符之间的逻辑上的间隔)  String phoneReg = "\\b(ip(hone|od)|android|opera m(ob|in)i" + "|windows (phone|ce)|blackberry"            + "|s(ymbian|eries60|amsung)|p(laybook|alm|rofile/midp" + "|laystation portable)|nokia|fennec|htc[-_]"            + "|mobile|up.browser|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";  String tableReg = "\\b(ipad|tablet|(Nexus 7)|up.browser" + "|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";
// 3.移动设备正则匹配:手机端、平板 Pattern phonePat = Pattern.compile(phoneReg, Pattern.CASE_INSENSITIVE); Pattern tablePat = Pattern.compile(tableReg, Pattern.CASE_INSENSITIVE); if (null == userAgent) { userAgent = ""; } // 4.匹配 Matcher matcherPhone = phonePat.matcher(userAgent); Matcher matcherTable = tablePat.matcher(userAgent); if (matcherPhone.find() || matcherTable.find()) { //来自手机或者平板 return true; } else { //来自PC return false; }}
复制代码


2)新建两个文件夹,将手机端和电脑端的 index 界面区分开来



(3)IndexController 代码改一下

import java.util.regex.Matcher;import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;
@Controllerpublic class IndexController {
@GetMapping("/") public String index(HttpServletRequest request) { if (isFromMobile(request)) { return "mp/index"; } else { return "web/index"; } }
/** * 校验是否手机端 * * @param request * @return */ public static boolean isFromMobile(HttpServletRequest request) { //1. 获得请求UA String userAgent = request.getHeader("USER-AGENT").toLowerCase(); //2.声明手机和平板的UA的正则表达式 // \b 是单词边界(连着的两个(字母字符 与 非字母字符) 之间的逻辑上的间隔), // 字符串在编译时会被转码一次,所以是 "\\b" // \B 是单词内部逻辑间隔(连着的两个字母字符之间的逻辑上的间隔) String phoneReg = "\\b(ip(hone|od)|android|opera m(ob|in)i" + "|windows (phone|ce)|blackberry" + "|s(ymbian|eries60|amsung)|p(laybook|alm|rofile/midp" + "|laystation portable)|nokia|fennec|htc[-_]" + "|mobile|up.browser|[1-4][0-9]{2}x[1-4][0-9]{2})\\b"; String tableReg = "\\b(ipad|tablet|(Nexus 7)|up.browser" + "|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";
// 3.移动设备正则匹配:手机端、平板 Pattern phonePat = Pattern.compile(phoneReg, Pattern.CASE_INSENSITIVE); Pattern tablePat = Pattern.compile(tableReg, Pattern.CASE_INSENSITIVE); if (null == userAgent) { userAgent = ""; } // 4.匹配 Matcher matcherPhone = phonePat.matcher(userAgent); Matcher matcherTable = tablePat.matcher(userAgent); if (matcherPhone.find() || matcherTable.find()) { //来自手机或者平板 return true; } else { //来自PC return false; } }}
复制代码


电脑端访问



手机端访问



到这里,一个接口区分电脑端和手机端的功能实现了,由于 index.html 引入了一些 js、css、ttf、woff 等静态资源,这些文件如何访问呢?继续看。


3. 其他类型的静态资源如何访问


mp目录下文件结构如下



index.html 想要引入 js 和 css 目录下的文件,路径应该这样写

<!DOCTYPE html><html><head>    <meta charset=utf-8>    <meta name=viewport content="width=device-width,initial-scale=1">    <title>summo-sbmy-front-mp</title>    <link href=/mp/css/app.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/mp/js/manifest.js></script><script type=text/javascript src=/mp/js/vendor.js></script><script type=text/javascript src=/mp/js/app.js></script></body></html>
复制代码


这样就可以访问到指定目录的资源了



整体逻辑其实很简单,我觉得最容易出问题的地方在路径的设置,有时候文件和代码都弄好了,但就是加载不出来,基本上就是路径设置错了。所以大家要是自己实现的话,尽量先按照我的文件路径来,先搞成功再说。


二、扩展知识


1. 给界面传递动态值


在 Spring MVC 中,将变量传递到视图通常通过 Model 对象或使用 ModelAndView 对象进行,举个例子:IndexController.java代码如下


package com.summo.file.controller;
// 确保引入相关的包import org.springframework.ui.Model;
@Controllerpublic class IndexController {
@GetMapping("/") public String index(HttpServletRequest request, Model model) { // 添加属性到model中 model.addAttribute("message", "欢迎访问我们的网站!"); // 设置一个版本号 model.addAttribute("version", "1.0.0");
// 根据客户端类型选择视图 if (isFromMobile(request)) { return "mp/index"; // 返回移动端页面 } else { return "web/index"; // 返回桌面端页面 } }}
复制代码


index.html代码如下

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head>  <title>首页</title>  <script type="text/javascript" th:src="'/mp/js/manifest-' + ${version} + '.js'"></script></head><body><h1>Hello World,我是电脑端</h1><!-- 在Thymeleaf中使用的表达式 --><p th:text="${message}"></p></body></html>
复制代码


访问之后可以看到参数已经替换掉了



动态传值在实际开发中经常使用到,比如我们一般在配置文件中维护好 js、css 的版本号,然后将版本号传给 index.html 达到动态控制前端版本。


2. 项目打包静态资源没有打进去


正常情况下,打完包后静态资源文件会在 static 文件夹下,但是上次我打包就发现静态资源文件没有打包进去,后来才知道需要在 pom.xml 文件里面配置一下,具体配置如下:

<build>    <finalName>summo-sbmy</finalName>    <resources>      <resource>        <!-- 指定配置文件所在的resource目录 -->        <directory>src/main/resources</directory>        <includes>          <include>**/*.html</include>          <include>**/*.js</include>          <include>**/*.css</include>        </includes>        <filtering>true</filtering>      </resource>      <resource>        <!-- 指定配置文件所在的resource目录 -->        <directory>src/main/resources</directory>        <includes>          <include>**/*.woff</include>          <include>**/*.ttf</include>        </includes>        <filtering>false</filtering>      </resource>    </resources>  </build> 
复制代码


这里需要注意的是,.woff 和.ttf 这类文件比较特殊,需要单独开一块并且设置 filtering 为 false。这个配置说明对这类文件不执行过滤,因为过滤可能破坏文件内容,字体文件应该以其原始形式包含在构建产物中。


三、总结一下


访问静态资源的接口大家接触的不多,主要是因为现在前后端分离了,前端自己使用 CDN 放资源,后端只用维护一个 index.html 文件,其他的资源都通过 CDN 访问,已经变得很简单了。但是有时候想要用却不知道从哪里开始,希望这篇文章可以给大家一个大概的思路,还有就是处理静态资源的框架很多,最常见的就是 Thymeleaf、Velocity,这两个都可以实现上面的效果,但建议不要混用。


文章转载自:sum 墨 

原文链接:https://www.cnblogs.com/wlovet/p/18143730

体验地址:http://www.jnpfsoft.com/?from=infoq


用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
网站的静态资源怎么获取?_网站_不在线第一只蜗牛_InfoQ写作社区