springboot后端作为代理返回前端代码。

17 篇文章 0 订阅
11 篇文章 0 订阅

背景介绍       

        在之前的一个文章中,我大致的介绍如果利用vue构建一个前端的成果物,然后在后端的springboot中部署。

       在这个例子中,我们的前端代码和后端代码被打成了统一的jar,然后使用java命令启动,这就uhi导致一个问题。当我们只需要更新前端代码时,会需要连同后端一起打包,并从新部署和重启。这种情况下是由风险的,完全比不上nginx作为代理的直接更新。

       所以想实现一个既可以像前后端不分离部署那样使用相同的上下文访问,又可以像nignx部署那样可单独更新。虽然这在现实情况下,机会没有应用的地方。但是谁让我想到了,那我就想试试可不可以。

       基于这个要求,就想如果可以实时更新且不影响后端代码,那就不能打成java包,又要同样的上下文访问。那就只能java自己返回前端的文件了。所以,只要指定好前端成果物文件的路径,然后通过指定的url就可以返回给前端这些文件。在需要跟新时,只需要更新这个文件夹即可。

这样就得到这样的代码:

后端代码

获取前端文件的url:/context/web/**

@RestController
@RequestMapping("/web")
public class IndexController {

    private static final CoreLogger LOGGER = CoreLoggerFactory.getLogger(IndexController.class);

    /**
     * 首页的访问
     * @param response 首页的html的流
     */
    @GetMapping({"/", "/index", "index.html"})
    public ResponseEntity<byte[]>  index(HttpServletResponse response){
        response.setHeader("Content-Type", "text/html;charset=UTF-8");

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.TEXT_HTML);
        //headers.add("Transfer-Encoding", "chunked");
        String name = "D:\\code\\self\\gitee\\core-manage-test-front\\dist\\index.html";
        File file = new File(name);
        try {
            ResponseEntity<byte[]> result = new ResponseEntity<byte[]>(FileUtil.readAsByteArray(file), headers, HttpStatus.OK);
            return result;
        } catch (IOException e) {
            LOGGER.error("访问首页错误", e);
        }
        return null;
    }

    /**
     * 文件的访问路径
     * @return 文件流
     */
    @GetMapping("/static/**")
    public ResponseEntity<InputStreamResource> getJsResource(HttpServletRequest request){
        String uri = request.getServletPath();
        LOGGER.info("获取文件:{}", uri);

        //截取/web/static后面的部分
        String filePath = uri.substring(11);
        // 创建File对象,表示要下载的文件
        File file = new File("D:\\code\\self\\gitee\\core-manage-test-front\\dist" +  filePath);

        String fileType = uri.substring(uri.lastIndexOf(".") + 1);

        // 将File转换为InputStream
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        // 创建InputStreamResource对象,将其作为文件流返回
        InputStreamResource resource = new InputStreamResource(inputStream);

        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, WebFileUtils.getContentType(fileType));
        headers.add("Vary","Access-Control-Request-Headers");
        headers.add("Vary","Access-Control-Request-Method");
        headers.add("Vary","Origin");
        
        // 创建ResponseEntity对象,将InputStreamResource作为响应体返回
        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(file.length())
                .body(resource);
    }
}

由于我们返回的是文件流,且浏览器要知道是什么的文件,所以我们要指定好返回接口的Content-Type:如果发现由其他的没有被定义的,需要持续的补充。

/**
 * 前端文件类型,对应的返回的 Content-Type
 */
public class WebFileUtils {

    private static Map<String, String> webContentType = new HashMap<>();

    static {
        //html文件
        webContentType.put("html", MediaType.TEXT_HTML_VALUE);
        //css文件
        webContentType.put("css", "text/css");
        //js文件
        webContentType.put("js", "application/javascript");

        //图片类型
        webContentType.put("jpg", "image/jpeg");
        webContentType.put("tiff", "image/tiff");
        webContentType.put("gif", "image/gif");
        webContentType.put("jfif", "image/jpeg");
        webContentType.put("png", "image/png");
        webContentType.put("tif", "image/tiff");
        webContentType.put("ico", "image/x-icon");
        webContentType.put("jpeg", "image/jpeg");
        webContentType.put("wbmp", "image/vnd.wap.wbmp");
        webContentType.put("fax", "image/fax");
        webContentType.put("net", "image/pnetvue");
        webContentType.put("jpe", "image/jpeg");
        webContentType.put("rp", "image/vnd.rn-realpix");
    }

    public static String getContentType(String fileType){
        return webContentType.get(fileType);
    }
}

通过以上的代码,只要是通过 /context/web/**发送过来的接口都当作是前端文件的请求。

前端代码

        前端按照正常新建一个vue项目,需要注意的是以下几个方面:

1. publicPath的配置,由于我们是访问后端拿的前端文件,假设我们后端项目的上下文是 /test1,则publicPath应该为:

publicPath: process.env.NODE_ENV === 'production' ? '/test1/web/static' : '/',

如果,没有上下文,就应该是:

publicPath: process.env.NODE_ENV === 'production' ? '/web/static' : '/',

       其实经过以上配置,基本上就可以访问到后端页面了,但是也有一个不足的地方,就是我们浏览器的标签页没有展示我们设置的图片信息。

public/index.html的配置了这个图片:

       虽然我也不知知道为什么没有去后端获取这个图片信息。但是既然你不取,那我就把你改成可以去获取的就行。 所以我在src下面创建了一个static文件,这里存了图片的地址。这里不可以放到asserts下,至于原因后面说明。然后在项目build的时候,将static中的文件复制到成果物的img下方。

复制的方法是利用插件:copy-webpack-plugin

在vue.config.js中做配置:

const {defineConfig} = require('@vue/cli-service')
const path = require('path');
//静态文件的复制操作
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = defineConfig({
    //...忽略原来的其他配置

    //复制static下面的文件
    configureWebpack: {
        plugins: [
            new CopyWebpackPlugin([
                // ./src/static是一个静态的文件,我们直接使用copy-webpack-plugin插件将文件复制到我们打包后的路径中,from为需要复制的文件的路径,还有一个to属性是复制到哪里的路径,不写则默认复制到打包后文件的根目录。
                {
                    from: path.resolve(__dirname, './src/static'),
                    to: path.resolve(__dirname, './dist/img')
                }
            ])
        ]
    }
})

public/index.html修改如下:加上了img的路径

如此大功告成。只需要i将这个成果物放到指定的文件夹下,就能实时更新了。也嫩通过后端访问了。

        这里附上vueconfig.js的完整代码:

const {defineConfig} = require('@vue/cli-service')
const path = require('path');
//静态文件的复制操作
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = defineConfig({
    transpileDependencies: true,
    publicPath: process.env.NODE_ENV === 'production' ? '/test1/web/static' : '/',
    devServer: {
        //以上的ip和端口是我们本机的;下面为需要跨域的
        proxy: {
            //由于前后端会部署到一台机器上,所以只要端口确定了就能保证可以访问到后端,IP用localhost就行
            '/': {
                ws: false,
                target: 'http://localhost:9998',
                changeOrigin: true,
                pathRewrite: {
                    '/^': '/'
                }
            }
        }
    },
    configureWebpack: {
        plugins: [
            new CopyWebpackPlugin([
                // ./src/static是一个静态的文件,我们直接使用copy-webpack-plugin插件将文件复制到我们打包后的路径中,from为需要复制的文件的路径,还有一个to属性是复制到哪里的路径,不写则默认复制到打包后文件的根目录。
                {
                    from: path.resolve(__dirname, './src/static'),
                    to: path.resolve(__dirname, './dist/img')
                }
            ])
        ]
    }
})

       之前说了为什么这个图片不能放到asserts下面。原因是,asserts下方的文件会被压缩,精简,筛选。只有在代码中使用了的才会被打包进去。而且名称也是不一样的。public/index.html不被认为是使用了图片。具体原因我(后端)不知道。 所以只能是通过复制的方式原封不动的复制过去。

        下一篇文章说一下怎么使用nginx来部署。嗯,希望我能搞懂先。

  • 29
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot后端返回图片给前端的过程中,可以通过以下几种方式实现: 1. 将图片存储在静态资源目录下,例如resources/static/images文件夹中。然后在接口中返回图片的URL地址。可以使用ServletUtils来获取生成图片的URL地址,并将其以JSON格式返回前端。\[1\] 2. 可以通过调用小程序的API,使用wx.chooseImage选择图片并上传到后端接口进行保存。在后端接口中,可以使用MultipartFile来接收上传的图片文件,并将其保存到指定的位置。然后将图片的URL地址返回前端。\[2\] 3. 另一种方式是将图片上传到文件服务器中,然后将图片的URL地址保存到数据库中。在前端页面中,可以通过HTTP访问该URL地址来显示图片。这样可以实现图片的上传和返回图片URL并展示的功能。\[3\] 以上是几种常见的方式,具体选择哪种方式取决于你的需求和实际情况。 #### 引用[.reference_title] - *1* [springboot 接口返回图片](https://blog.csdn.net/shuaiqijiejie/article/details/127155499)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [SpringBoot与微信小程序进行图片的上传和后端返回图片url在前端展示](https://blog.csdn.net/qq_43712169/article/details/123661241)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值