首页 > 其他分享 >记一次拆分前后端模块部署Jar过程

记一次拆分前后端模块部署Jar过程

时间:2022-10-30 10:00:46浏览次数:44  
标签:index 拆分 Jar loader webpack registry 模块 org true


背景

单体应用,前端使用React框架,静态资源(JS,CSS等)都放在​​src\main\resources\static​​目录下面:

.babelrc
.gitignore
.mvn
node_modules
package-lock.json
package.json
pom.xml
src
--main
--java
--resources
--static
--templates
--dist
webpack.config.js

此时的前端构建配置文件​​webpack.config.js​​:

var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin')

let devServer = {}
let plugins = [
new webpack.DefinePlugin({
ISDEV: JSON.stringify(process.env.NODE_ENV === 'development'),
}),
new HtmlWebpackPlugin({
template: "./src/main/resources/templates/index.html",
// ?
inject: true
}),
]
if (process.env.NODE_ENV === 'development') {
devServer = {
contentBase: path.join(__dirname, './src/main/resources/templates/dist'),
host: 'localhost',
port: '8000',
open: true, // 自动拉起浏览器
hot: true, // 热加载
}
plugins.push(new webpack.HotModuleReplacementPlugin())
}

module.exports = {
entry: './src/main/resources/static/index.js',
output: {
path: path.resolve(__dirname, './src/main/resources/templates/dist'),
publicPath: process.env.NODE_ENV === 'development' ? '' : './templates/dist/',
filename: process.env.NODE_ENV === 'development' ? 'build.js' : 'build.[chunkhash].js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', "@babel/preset-react"],
plugins: ['@babel/plugin-proposal-object-rest-spread', "@babel/plugin-proposal-function-bind", '@babel/plugin-proposal-class-properties']
}
},
// {
// loader: 'eslint-loader', // 指定启用eslint-loader
// options: {
// formatter: require('eslint-friendly-formatter'),
// emitWarning: false
// }
// }
]
},
{
test: /\.(scss|css|less)$/,
exclude: /node_modules/, // 用于自定义样式处理,需去除node_modules文件夹
use: [{
loader: "style-loader"
}, {
loader: "css-loader",
options: {
modules: true, // 采用className={styles.xxx}的方式进行添加样式
localIdentName: '[local]--[hash:base64:5]'
}
}, {
loader: "less-loader",
}]
},
{
test: /\.(scss|css|less)$/,
include: /node_modules/, // 用于antd, 需包括node_modules
use: [{
loader: "style-loader"
}, {
loader: "css-loader",
}, {
loader: "less-loader",
options: {
modifyVars: {
// 自定义主题色
"primary-color": "#6E54B0",
"link-color": "#6E54B0",
'border-radius-base': '2px',
},
javascriptEnabled: true,
}
}]
},
{
test: /\.(eot|ttf|woff|woff2)(\?\S*)?$/,
loader: 'file-loader'
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
extensions: ['.js', '.jsx', '.json'],
},
performance: {hints: false},
plugins: plugins,
devServer
}

前端​​package.json​​文件没什么特殊之处:

{
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "set NODE_ENV=development&& webpack --mode=development",
"pre": "set NODE_ENV=development&& webpack --mode=development",
"prod": "set NODE_ENV=production&& webpack --mode=production",
"start": "set NODE_ENV=development&&webpack-dev-server --mode development --port=8001"
}
}

后端有一个配置文件​​StaticResourcesConfig.java​​:

@Configuration
public class StaticResourcesConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");
super.addResourceHandlers(registry);
}

// 无关此文主题,解决跨域的配置
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.maxAge(3600)
.allowCredentials(true);
}
}

现在,想要做前后端分离,此为背景。

实践

项目架构调整:

记一次拆分前后端模块部署Jar过程_maven


根目录​​pom.xml​​:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aaa.framework.microservice</groupId>
<artifactId>microservice-starter-parent</artifactId>
<version>1.1.9</version>
</parent>
<groupId>com.aaa.cbd.platform</groupId>
<artifactId>octopus-backend-parent</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<modules>
<module>octopus-backend-ui</module>
<module>octopus-backend</module>
</modules>

<properties>
<module.version>1.0.0-SNAPSHOT</module.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.aaa.cbd.platform</groupId>
<artifactId>octopus-backend</artifactId>
<version>${module.version}</version>
</dependency>
<dependency>
<groupId>com.aaa.cbd.platform</groupId>
<artifactId>octopus-backend-ui</artifactId>
<version>${module.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<verbose>true</verbose>
<fork>true</fork>
<compilerVersion>${java.version}</compilerVersion>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

后端​​pom.xml​​文件依赖于前端构建产物Jar:

<project>
<parent>
<groupId>com.aaa.cbd.platform</groupId>
<artifactId>octopus-backend-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>octopus-backend</artifactId>

<properties>
<octopus-backend-ui.version>1.0.0-SNAPSHOT</octopus-backend-ui.version>
</properties>

<dependencies>
<dependency>
<groupId>com.aaa.cbd.platform</groupId>
<artifactId>octopus-backend-ui</artifactId>
<version>${octopus-backend-ui.version}</version>
</dependency>
</dependencies>
</project>

而前端工程的​​pom.xml​​文件配置如下:

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.aaa.cbd.platform</groupId>
<version>1.0.0-SNAPSHOT</version>
<artifactId>octopus-backend-ui</artifactId>
<properties>
<build-plugin.exec.version>1.4.0</build-plugin.exec.version>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>exec-npm-install</id>
<phase>validate</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>npm</executable>
<arguments>
<argument>install</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>npm-build</id>
<phase>generate-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>npm</executable>
<arguments>
<argument>run</argument>
<argument>build</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>woff</nonFilteredFileExtension>
<nonFilteredFileExtension>ttf</nonFilteredFileExtension>
<nonFilteredFileExtension>woff2</nonFilteredFileExtension>
<nonFilteredFileExtension>eot</nonFilteredFileExtension>
<nonFilteredFileExtension>swf</nonFilteredFileExtension>
<nonFilteredFileExtension>ico</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>dist</directory>
<targetPath>META-INF/ui</targetPath>
<filtering>true</filtering>
</resource>
</resources>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${build-plugin.exec.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

前端​​webpack.config.js​​仅列出有变化的部分:

let plugins = [
new HtmlWebpackPlugin({
// change 1
template: "./index.html",
}),
]
if (process.env.NODE_ENV === 'development') {
devServer = {
// change 2
contentBase: path.join(__dirname, './dist'),
host: 'localhost',
port: '8000',
open: true,
hot: true,
}
plugins.push(new webpack.HotModuleReplacementPlugin())
}

module.exports = {
// change 3
entry: './src/index.js',
output: {
// change 4
path: path.resolve(__dirname, './dist'),
// change 5
publicPath: process.env.NODE_ENV === 'development' ? '' : './',
filename: process.env.NODE_ENV === 'development' ? 'build.js' : 'build.[chunkhash].js'
}
}

根据父工程的pom文件配置,打开maven面板,先执行clean然后执行install:

记一次拆分前后端模块部署Jar过程_xml_02


可以得到如下构建产物:

记一次拆分前后端模块部署Jar过程_xml_03


可以发现:前端工程会打包为一个Jar,并作为一个依赖放在后端Spring Boot应用Jar包里面。

此时,我们可以启动应用:​​java -jar -Dserver.port=8082 octopus-backend-1.0.0-SNAPSHOT.jar​

浏览器输入:http://localhost:8082/hs,返回响应OK。因为我们写有一个应用健康状态Controller接口:

@RestController
public class HealthController {
@RequestMapping(value = "/hs")
public String hs() {
return "OK";
}

问题来了,怎么访问前端页面呢?

答案是:StaticResourcesConfig配置文件。

之前的配置为:
​​​registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");​

我们替换为:
​​​registry.addResourceHandler("/static/**").addResourceLocations("classpath:/META-INF/");​

同时​​pom.xml​​文件更新为:

<resources>
<resource>
<directory>dist</directory>
<targetPath>META-INF/static</targetPath>
<filtering>true</filtering>
</resource>
<resources>

然后浏览器输入:http://localhost:8082/static/static/index.html#/,可以访问:

记一次拆分前后端模块部署Jar过程_xml_04


如何去掉两层static嵌套呢?

血与泪的尝试,​​ResourceHandler​​​一定要是两层目录:
​​​registry.addResourceHandler("/**/**").addResourceLocations("classpath:/META-INF/");​

同时​​pom.xml​​文件更新为:

<resources>
<resource>
<directory>dist</directory>
<targetPath>META-INF/</targetPath>
<filtering>true</filtering>
</resource>
</resources>

解压缩前端工程Jar包:

记一次拆分前后端模块部署Jar过程_xml_05


发现dist文件夹复制到​​META-INF​​目录下。

新问题

浏览器打开登录页
​ http://localhost:8082/index.html#/​​

登录成功后进入首页: 404
​ http://localhost:8082/index​​

实际上能够正常显示的 首页:
​ http://localhost:8082/index.html#/index​​

其他页面:
​ http://localhost:8082/index.html#/appList​​

言外之意,页面需要再嵌套加一层​​index.html#/​

怎么解决这个问题呢?看起来是前端路径的问题,此时如果把精力放在前端构建文件​​webpack.config.js​​,则是走了弯路。

最后的解决方法,还是配置​​StaticResourcesConfig​​文件:

package config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class StaticResourcesConfig extends WebMvcConfigurerAdapter {
@Value("${server.contextPath:}")
private String contextPath;

@Value("${applications.indexForwardPath:index.html}")
private String forwardPath;

@Value("${applications.resourceLocations:classpath:/static/,classpath:/public/}")
private String resourceLocations;

@Override
public void addViewControllers(ViewControllerRegistry registry) {
// contextPath为空,if条件不成立
if (StringUtils.hasText(contextPath)) {
registry.addRedirectViewController(contextPath, contextPath + "/");
}
// 下面两个addViewController有什么区别
registry.addViewController(contextPath + "/").setViewName(forwardPath);
registry.addViewController("/*/").setViewName("forward:index.html");
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
resourceLocations += ",classpath:/META-INF/";
registry.addResourceHandler("/**")
.addResourceLocations(resourceLocations.split(","))
.resourceChain(true);
}
}

另外还要去掉一个Controller:

@RequestMapping("")
@Controller
public class UserController {
@GetMapping
public String goToLogin() {
return "dist/index";
}
}


标签:index,拆分,Jar,loader,webpack,registry,模块,org,true
From: https://blog.51cto.com/u_15851118/5807209

相关文章