Spring Boot React在单独的软件包中

时间:2019-07-15 20:36:32

标签: java spring reactjs spring-boot jhipster

我有一个Spring Boot Java 8 API,我想添加一个React前端以使API操作更易于浏览和使用。我使用JHipster生成器生成React应用。然后,我只是将Web部分放到了我的应用程序中,但是每当我运行Spring Boot应用程序并尝试导航到它的端口:8080时,我都会得到以下页面:

enter image description here

以及控制台中的以下错误:

2019-07-15 15:07:21.414  INFO 29145 --- [)-10.15.114.229] o.a.c.c.C.[.[.[/]                                            : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-07-15 15:07:21.414  INFO 29145 --- [)-10.15.114.229] o.s.w.s.DispatcherServlet                                    : Initializing Servlet 'dispatcherServlet'
2019-07-15 15:07:21.414 DEBUG 29145 --- [)-10.15.114.229] o.s.w.s.DispatcherServlet                                    : Detected StandardServletMultipartResolver
2019-07-15 15:07:21.426 DEBUG 29145 --- [)-10.15.114.229] o.s.w.s.DispatcherServlet                                    : enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
2019-07-15 15:07:21.426  INFO 29145 --- [)-10.15.114.229] o.s.w.s.DispatcherServlet                                    : Completed initialization in 12 ms
2019-07-15 15:07:25.079 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.DispatcherServlet                                    : GET "/", parameters={}
2019-07-15 15:07:25.093 DEBUG 29145 --- [nio-8080-exec-1] s.d.s.w.PropertySourcedRequestMappingHandlerMapping          : looking up handler for path: /
2019-07-15 15:07:25.128 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.h.SimpleUrlHandlerMapping                            : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
2019-07-15 15:07:25.130 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler                         : Resource not found
2019-07-15 15:07:25.131 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.DispatcherServlet                                    : Completed 404 NOT_FOUND
2019-07-15 15:07:25.152 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.DispatcherServlet                                    : "ERROR" dispatch for GET "/error", parameters={}
2019-07-15 15:07:25.153 DEBUG 29145 --- [nio-8080-exec-1] s.d.s.w.PropertySourcedRequestMappingHandlerMapping          : looking up handler for path: /error
2019-07-15 15:07:25.167 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.m.m.a.RequestMappingHandlerMapping                   : Mapped to public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2019-07-15 15:07:25.199 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver                     : Selected 'text/html' given [text/html, text/html;q=0.8]
2019-07-15 15:07:25.208 DEBUG 29145 --- [nio-8080-exec-1] o.s.w.s.DispatcherServlet                                    : Exiting from "ERROR" dispatch, status 404

这是我的项目结构:

FooApplication
├── build.gradle
├── api/
    ├── src.main.java.com.foo/
            ├── FooApplication.java
    └── build.gradle
├── web/
    ├── node_modules/
    ├── src.main.webapp/
        ├── app/
            ├── index.tsx
            ├── routes.tsx
            └── app.tsx
        └── index.html
    ├── webpack/
        └── webpack.common.js
    └── build.gradle

这是我的webpack.common.js文件:

const webpack = require('webpack');
const {BaseHrefWebpackPlugin} = require('base-href-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const path = require('path');

const utils = require('./utils.js');

const getTsLoaderRule = env => {
  const rules = [
    {
      loader: 'cache-loader',
      options: {
        cacheDirectory: path.resolve('build/cache-loader')
      }
    },
    {
      loader: 'thread-loader',
      options: {
        // There should be 1 cpu for the fork-ts-checker-webpack-plugin.
        // The value may need to be adjusted (e.g. to 1) in some CI environments,
        // as cpus() may report more cores than what are available to the build.
        workers: require('os').cpus().length - 1
      }
    },
    {
      loader: 'ts-loader',
      options: {
        transpileOnly: true,
        happyPackMode: true
      }
    }
  ];
  if (env === 'development') {
    rules.unshift({
      loader: 'react-hot-loader/webpack'
    });
  }
  return rules;
};

module.exports = options => ({
  cache: options.env !== 'production',
  resolve: {
    extensions: [
      '.js', '.jsx', '.ts', '.tsx', '.json'
    ],
    modules: ['node_modules'],
    alias: {
      app: utils.root('src/main/webapp/app/')
    }
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: getTsLoaderRule(options.env),
        include: [utils.root('./src/main/webapp/app')],
        exclude: [utils.root('node_modules')]
      },
      {
        test: /\.(jpe?g|png|gif|svg|woff2?|ttf|eot)$/i,
        loader: 'file-loader',
        options: {
          digest: 'hex',
          hash: 'sha512',
          name: 'content/[hash].[ext]'
        }
      },
      {
        enforce: 'pre',
        test: /\.jsx?$/,
        loader: 'source-map-loader'
      },
      {
        test: /\.tsx?$/,
        enforce: 'pre',
        loader: 'tslint-loader',
        exclude: [utils.root('node_modules')]
      }
    ]
  },
  stats: {
    children: false
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        commons: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: `'${options.env}'`,
        VERSION: `'${utils.parseVersion()}'`,
        DEBUG_INFO_ENABLED: options.env === 'development',
        // The root URL for API calls, ending with a '/' - for example: `"https://www.jhipster.tech:8081/myservice/"`.
        // If this URL is left empty (""), then it will be relative to the current context.
        // If you use an API server, in `prod` mode, you will need to enable CORS
        // (see the `jhipster.cors` common JHipster property in the `application-*.yml` configurations)
        SERVER_API_URL: `''`
      }
    }),
    new ForkTsCheckerWebpackPlugin({tslint: true}),
    new CopyWebpackPlugin([
      {from: './node_modules/swagger-ui/dist/css', to: 'swagger-ui/dist/css'},
      {from: './node_modules/swagger-ui/dist/lib', to: 'swagger-ui/dist/lib'},
      {from: './node_modules/swagger-ui/dist/swagger-ui.min.js', to: 'swagger-ui/dist/swagger-ui.min.js'},
      {from: './src/main/webapp//swagger-ui/', to: 'swagger-ui'},
      {from: './src/main/webapp/static/', to: 'content'},
      {from: './src/main/webapp/favicon.ico', to: 'favicon.ico'},
      {from: './src/main/webapp/manifest.webapp', to: 'manifest.webapp'},
      // jhipster-needle-add-assets-to-webpack - JHipster will add/remove third-party resources in this array
      {from: './src/main/webapp/robots.txt', to: 'robots.txt'}
    ]),
    new HtmlWebpackPlugin({
      template: './src/main/webapp/index.html',
      chunksSortMode: 'dependency',
      inject: 'body'
    }),
    new BaseHrefWebpackPlugin({baseHref: '/'}),
  ]
});

导航到index.html时如何获得spring boot来提供localhost:8080文件?我知道我将不得不覆盖一些默认的Spring Boot配置才能使其正常工作,但是我不清楚什么配置。

我可以根据要求提供更多文件的详细信息,只是不想让不必要的信息超载。

2 个答案:

答案 0 :(得分:0)

为应用程序的入口点请求映射,读取文件,然后返回内容。就我而言,React代码存储在/tmp/build/index.html。简化并忽略了错误,看起来可能像这样:

    @RequestMapping(
            value = "",
            method = RequestMethod.GET)
    public ResponseEntity<String> getIndexContent() {
        final File file = new File("/tmp/build/index.html");
        final String content =
                FileUtils.readFileToString(
                        file,
                        StandardCharsets.UTF_8);
        return ResponseEntity
                .ok()
                .contentType(MediaType.TEXT_HTML)
                .body(content);
    }

答案 1 :(得分:0)

Spring-boot默认将某些路径自动配置为静态资源位置:return these 3 ids# example data mydata = np.array([0.85405058, 0.78228784, np.nan, 0.72828138, 0.73757833, 0.69303712, 0.5730553, 0.57644895]) dates_list = [datetime.date(2017, 1, 5), datetime.date(2017, 5, 22), datetime.date(2017, 6, 14), datetime.date(2017, 8, 17), datetime.date(2017, 9, 27), datetime.date(2017, 10, 6), datetime.date(2017, 11, 23), datetime.date(2017, 12, 28)] months_list= [1, 5, 6, 8, 9, 10, 11, 12] # plot data fig, ax = plt.subplots(1,1) ax.scatter(dates_list,mydata,s=30,c=months_list,cmap='viridis') /static。参见Official Spring Docs

因此,如果您可以将index.html和相关资产移动到静态资源路径中,则Spring Boot应该按原样提供它们。
另外,就像那些文档所说的那样,您可以通过设置/public属性来将新路径添加为静态位置。

要做的一件好事是构建您的React应用程序,捆绑资源,并将捆绑的资产+ index.html复制到Spring项目的静态位置。

您还没有提到有关构建设置的任何信息,如果您将Gradle Node Plugin与Webpack一起使用,那么这并不难。 blog post展示了您将如何操作(但是,不要使用多个模块)