前言
前后端分离开发模式让前后端开发只需要专注于前端或后端的开发工作,提升开发效率,可以实现前后端代码的解耦。同时,如果能做到前后端部署分离,可减少后端服务器的压力,后端服务器也不再需要处理静态资源。不过,由于环境或者是技术的原因,有时候没办法做到前端服务器独立部署的情况。针对这种情况,可以采用开发独立,合并部署的方式,在后端系统构建时将前端系统合并到后端打包,然后只需要将后端部署到应用服务器上。
一、springboot与vue合并
前端项目执行npm run build
命令进行打包,会自动生成打包后的dist目录文件,如下图:
把dist/static目录下的所有文件都拷贝到springboot项目的resources/static目录下,dist下的index.html文件拷贝到springboot项目的resources下,如下图:
二、合并后出现的问题
1. static目录下的静态资源无法访问
重新指定springboot的静态资源映射地址:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
}
2. vue-router路由的路径无法正常解析
将vue-router中的路径加上统一的前缀“/vue
”,然后在springboot项目中自定义过滤器,拦截带“/vue
”的路径,将请求转发到“/index.html
”(将vue的路由资源交给路由处理)。
过滤器定义:
public class VueFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
// 开始转发
servletRequest.getRequestDispatcher("/index.html").forward(servletRequest, servletResponse);
}
}
过滤器注册:
@Bean
public FilterRegistrationBean filterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
// 注册vue过滤器
registration.setFilter(new VueFilter());
registration.addUrlPatterns("/vue/*");
registration.setName("vueFilter");
return registration;
}
三、本地调试
频繁的修改前端页面拷贝打包到后端,操作比较麻烦,所以正常在本地启动项目进行调试的过程中,都是本地前后端分开启动进行联调(端口号必须不一致,否则会提示端口号被占用),此时后端的controller需要支持跨域
,否则本地前端vue前端系统调用后端的接口会出现不支持跨域的相关报错。
@CrossOrigin
注解表示此方法支持跨域
,eg:
@CrossOrigin
@RequestMapping(value = "/login.do", method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
@ResponseBody
public Map<String, Object> login(@RequestBody Map<String, String> map) {
String userName = map.get("userName");
String userPwd = map.get("userPwd");
Map<String, Object> resMap = new HashMap<>();
if ("admin".equals(userName) && "123456".equals(userPwd)) {
resMap.put("result", "T");
} else {
resMap.put("result", "F");
resMap.put("message", "用户名/密码错误!!!");
}
return resMap;
}