Spring boot and Vue deployment solutions you don't know

Eternal clouds 2020-11-09 12:33:12
spring boot vue deployment solutions


Preface

Some time ago, the demonstration environment of the company's external network deployment was all transferred to the Intranet environment , All external demonstration environments need to apply for external network mapping to access a certain service . I use an Internet address www.a.com Mapping to an intranet address http://ip:port, And then at this address http://ip:port use nginx Acting as a proxy to forward items to groups http://ipn:portn Up , There are also some static resources 404, The main thing is to solve this problem 404 problem .

I've done another project recently , Considering the user experience , Reduce the complexity of deployment , I thought of a way to use SpringBoot do web Server mapping front-end resources are web resources .

<font color=red> Conditions permit or require high performance , It is recommended that the front and rear end be deployed separately ,nginx do web The server , The back end only provides interface services </font>

Previously deployed projects A The Internet access address is http://ip1:8080, After mapping, you can only access http://ip/app1 , Previous projects B The Internet access address is http://ip1:8081 , The project address is http://ip/app2 . This is not a small change , But the first problem after switching is that static resource forwarding leads to 404.

For example, previous projects A The address is http://ip1:8080 It has no context .

And now A The address of is http://ip/app1 , There is a context app1 ad locum , It leads to some resources 404.

for instance : original http://ip1:8080 Request arrived. index.html resources , Now we can only http://ip/app1 Ask to index.html.

<!-- index.html -->
<!-- The original deployment environment is written in -->
<link href="/index.css" rel="stylesheet">

Previously visited index.css The address is http://ip1:8080/index.css , But now it's an interview http://ip/index.css Lead to 404, actual index.css The address is http://ip/app1/index.css

Front end use vue To write ,html The static resource path in can be well solved , modify webpack Just pack it .

<!-- The original deployment environment is written in -->
<link href="/index.css" rel="stylesheet">
<!-- Write it as a relative path -->
<link href="./index.css" rel="stylesheet">
<!-- combination webpack Path supplement when packing -->
<link href="<%= BASE_URL %>index.css" rel="stylesheet">

However, there are some component requests in the project that cannot be handled uniformly , You can only change the code . But I don't want to move code ,webpack I don't want to move the package , Based on these needs, I think of a way to solve .

The content of this article is

  • Nginx Deploy vue project , How to handle the loss of static resources in a friendly way
  • SpringBoot Provide web Function mapping of the server vue The project is web resources , And deal with vue Routing and forwarding index.html problem .

Demo code address

https://github.com/zhangpanqin/vue-springboot

Nginx Deploy Vue project

server {
listen 8087;
# Its function is not to redirect addresses , For example, browser input /app1 visit , You can also visit /app1/ , And the browser address doesn't change /app1 . Can't , Obsessive compulsive disorder 
location / {
try_files $uri $uri/;
}
root /Users/zhangpanqin/staic/;
location ~ /(.*)/ {
index index.html /index.html;
try_files $uri $uri/ /$1/index.html;
}
}

/Users/zhangpanqin/staic/ Put deployed projects , such as app Project resources are put into /Users/zhangpanqin/staic/app Next . The visiting address is http://ip/8087/app

<!DOCTYPE html>
<html lang="en">
<head>
<!-- It can also be changed to a similar address BASE_URL be equal to vue.config.js Configured publicPath-->
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- After deployment , Can't access index.css -->
<link href="/index.css" rel="stylesheet">
</head>
</html>

In order to be able to enter vue The routing /app/blog You can also visit the page , Need to add vue-router Medium base attribute .

import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'Home',
component: () => import('@/views/Home.vue'),
},
{
path: '/blog',
name: 'Blog',
component: () => import('@/views/Blog.vue'),
},
{
// Jump here when the route cannot be matched 
path: '*',
name: 'Error404',
component: () => import('@/views/Error404.vue'),
}
];
const router = new VueRouter({
// It's mainly to modify here , According to vue mode Environment .
// https://cli.vuejs.org/zh/guide/mode-and-env.html
// https://router.vuejs.org/zh/api/#base
base: process.env.VUE_APP_DEPLOY_PATH,
mode: 'history',
routes,
});
export default router;

<img src="http://oss.mflyyou.cn/blog/20200727234702.png?author=zhangpanqin" alt="image-20200727234702928" style="zoom: 25%;" />

http://localhost:8087/app/index.css by css The real address of . So try to find a way not to /app Resources at the beginning plus /app That's all right. , After thinking about it, only cookie Can do .

x_vue_path Record the path of each project , Then static resources go to this path to find ,$cookie_x_vue_path/$uri

The following configuration uses try_files Internal redirection resources , There will be no redirection on on the browser side .

# gzip , cache and epoll None of the optimized ones have been written 
server {
listen 8087;
# Its function is not to redirect addresses , For example, browser input /app1 visit , You can also visit /app1/ , And the browser address doesn't change /app1 . Can't , Obsessive compulsive disorder 
location / {
try_files $uri $uri/;
}
root /Users/zhangpanqin/staic/;
# (.*) Which item is the match , for instance app1 app2 etc. 
location ~ /(.*)/.*/ {
index index.html /index.html;
add_header Set-Cookie "x_vue_path=/$1;path=/;";
# /Users/zhangpanqin/staic/+/$1/index.html You can go to each project index.html
try_files $uri $uri/ /$1/index.html @404router;
}
# Find static resources , You can also add a cache here .
location ~ (.css|js)$ {
try_files $uri $cookie_x_vue_path/$uri @404router;
}
location @404router {
return 404;
}
}

image-20200728014849158

Here is the redirection configuration

server {
listen 8087;
root /Users/zhangpanqin/staic/;
location ~ /(.*)/.*/? {
index index.html /index.html;
add_header Set-Cookie "x_vue_path=/$1;path=/;";
try_files $uri $uri/ /$1/index.html @404router;
}
location ~ (.css|js)$ {
# Match to /app/index.css Resources for , Direct access 
rewrite ^($cookie_x_vue_path)/.* $uri break;
# Resources accessed /index.css 302 Temporarily redirect to /app/index.css
rewrite (.css|js)$ $cookie_x_vue_path$uri redirect;
}
location @404router {
return 404;
}
}

image-20200728014654144

According to this idea, all resources can be forwarded , Don't change the business code , Just give vue-router Add a base Basic routing .

SpringBoot Deploy Vue project

Nginx It's working ,SpringBoot Just follow the gourd and draw the gourd , still java It's comfortable to write , can debug, ha-ha .

SpringBoot Mapping static resources

@Configuration
public class VueWebConfig implements WebMvcConfigurer {
/**
* Mapped static resource path
* file:./static/ Path is relative to user.dir route ,jar Package under the same level directory static
*/
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {"file:./static/", "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/"};
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// Add static resource cache 
CacheControl cacheControl = CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic();
registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS).setCacheControl(cacheControl);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// Configure the resources to intercept , It is mainly used for add to cookie 
registry.addInterceptor(new VueCookieInterceptor()).addPathPatterns("/test/**");
}
// vue Routing forwarding uses , Also do Interface request not found 
@Bean
public VueErrorController vueErrorController() {
return new VueErrorController(new DefaultErrorAttributes());
}
}

Project static resource path add cookie

public class VueCookieInterceptor implements HandlerInterceptor {
public static final String VUE_HTML_COOKIE_NAME = "x_vue_path";
public static final String VUE_HTML_COOKIE_VALUE = "/test";
/**
* Configure the request resource path /test Add all the following cookie
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
final Cookie cookieByName = getCookieByName(request, VUE_HTML_COOKIE_NAME);
if (Objects.isNull(cookieByName)) {
final Cookie cookie = new Cookie(VUE_HTML_COOKIE_NAME, VUE_HTML_COOKIE_VALUE);
// Under the project of url You can take it with you 
cookie.setPath("/");
cookie.setHttpOnly(true);
response.addCookie(cookie);
}
return true;
}
public static Cookie getCookieByName(HttpServletRequest httpServletRequest, String cookieName) {
final Cookie[] cookies = httpServletRequest.getCookies();
if (Objects.isNull(cookieName) || Objects.isNull(cookies)) {
return null;
}
for (Cookie cookie : cookies) {
final String name = cookie.getName();
if (Objects.equals(cookieName, name)) {
return cookie;
}
}
return null;
}
}

Request error to forward resources

The wrong jump should be clearly distinguished Interface requests and static resource requests , adopt accept Can be judged .

@RequestMapping("/error")
public class VueErrorController extends AbstractErrorController {
private static final String ONLINE_SAIL = VUE_HTML_COOKIE_NAME;
private static final String ERROR_BEFORE_PATH = "javax.servlet.error.request_uri";
public VueErrorController(DefaultErrorAttributes defaultErrorAttributes) {
super(defaultErrorAttributes);
}
@Override
public String getErrorPath() {
return "/error";
}
@RequestMapping
public ModelAndView errorHtml(HttpServletRequest httpServletRequest, HttpServletResponse response, @CookieValue(name = ONLINE_SAIL, required = false, defaultValue = "") String cookie) {
final Object attribute = httpServletRequest.getAttribute(ERROR_BEFORE_PATH);
if (cookie.length() > 0 && Objects.nonNull(attribute)) {
response.setStatus(HttpStatus.OK.value());
String requestURI = attribute.toString();
// The access path is not to vue End of deployment path , Add path forwarding to access 
if (!requestURI.startsWith(cookie)) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setStatus(HttpStatus.OK);
// Static resources don't want to forward , Redirect words , It is amended as follows redirect
String viewName = "forward:" + cookie + requestURI;
modelAndView.setViewName(viewName);
return modelAndView;
}
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.setStatus(HttpStatus.OK);
modelAndView.setViewName("forward:/test/index.html");
return modelAndView;
}
// The processing request header is accept by application/json Request , The interface request returns json data 
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
HttpStatus status = getStatus(request);
if (status == HttpStatus.NO_CONTENT) {
return new ResponseEntity<>(status);
}
final Map<String, Object> errorAttributes = getErrorAttributes(request, true);
return new ResponseEntity<>(errorAttributes, status);
}

Home page Jump

@Controller
public class IndexController {
@RequestMapping(value = {"/test", "/test"})
public String index() {
return "forward:/test/index.html";
}
}

This paper is written by Zhang Panqin's blog http://www.mflyyou.cn/ A literary creation . Reprint freely 、 quote , But you need to sign the author and indicate the source of the article .

For example, the official account of WeChat , Please add the author's official account number 2 . WeChat official account name :Mflyyou

版权声明
本文为[Eternal clouds]所创,转载请带上原文链接,感谢

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云