SpringBoot+React 前后端分离

SpringBoot+React 前后端分离

后端

简单用 SpringBoot 起个服务,写个接口处理请求:

@RestController
@RequestMapping("/data")
public class DataController {

    @Autowired
    HttpRequestService httpRequestService;

    @Autowired
    TestService testService;

    @RequestMapping("/test")
    public List<?> reportTest(@RequestParam("file") MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();
        System.out.println(file.getName());
        List<TestEntity> testEntities = testService.DataListRead(inputStream, file.getOriginalFilename());
        httpRequestService.postTest(JSON.toJSONString(testEntities));
        // 进行文件的读取和处理操作
        return testEntities;
    }
}

我这个方法的具体业务就是接收前端请求传来的文件,调用 Service 解析内容并转发出去。直接返回解析后的对象列表了,这是不太好的,应该封装一个 ResponseBody 才对,但我这就随意了。

后端 SpringBoot 默认的端口是 8080,启动后放着就可以了。

前端

前端在 VSCode 中使用 NPM 初始化一个纯净的React项目,然后按步骤补充几个关键文件:

  1. App.js,应用程序最大的组件;
  2. index.html,页面入口;
  3. index.js,将 App 渲染到页面上;
  4. style.css,让页面好看的(可选)。

首先是 App.js 组件:

import React, { useState } from 'react';
import axios from 'axios';
import './style.css';  // 引入样式文件

function FileUpload() {
  const [file, setFile] = useState(null);
  const [interfaceType, setInterfaceType] = useState(null);

  const handleSubmit = async (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append('file', file);

    let url = '';
    switch (interfaceType) {
      case 'test':
        url = 'http://localhost:8080/data/test';
        break;
      case 'vehicle':
        url = 'http://localhost:8080/data/vehicle';
        break;
      case 'battery':
        url = 'http://localhost:8080/data/battery';
        break;
      default:
        return;
    }

    try {
      const res = await axios.post(url, formData, {
        headers: {
          'Content-Type': 'multipart/form-data'
        }
      });
      console.log(res);
      alert('文件上传成功');
    } catch (error) {
      console.error(error);
      alert('文件上传失败');
    }
  };

  return (
    <div>
      {/* <h1>文件上传</h1> */}
      <form onSubmit={handleSubmit}>
        <div>
          <label htmlFor="fileInput">请选择文件:</label>
          <input type="file" id="fileInput" accept=".xls,.xlsx" onChange={(e) => setFile(e.target.files[0])} />
        </div>
        <div>
          <label htmlFor="testOption">测试数据 </label>
          <input type="radio" name="interface" id="testOption" value="test" onChange={(e) => setInterfaceType(e.target.value)} />
        </div>
        <div>
          <label htmlFor="vehicleOption">车辆数据 </label>
          <input type="radio" name="interface" id="vehicleOption" value="vehicle" onChange={(e) => setInterfaceType(e.target.value)} />
        </div>
        <div>
          <label htmlFor="batteryOption">电池数据 </label>
          <input type="radio" name="interface" id="batteryOption" value="battery" onChange={(e) => setInterfaceType(e.target.value)} />
        </div>
        <div>
          <button type="submit">提交</button>
        </div>
      </form>
    </div>
  );
}

export default FileUpload;

仅由一个组件构成,其中使用了 axios 发送请求,参考 AXIOS 文档。

然后是 index.js 文件,将组件渲染到页面上:

import React from 'react';
import ReactDOM from 'react-dom/client';
import FileUpload from './App';

//ReactDOM.render(<FileUpload />, document.getElementById('root'));
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<FileUpload />);

由于使用 NPM 安装的 React 是18版本的,因此 ReactDOM.render 方法已经被弃用了,需要换成 ReactDOM.createRoot 方法,大同小异。

HTML 页面和 CSS 样式就不用放了,一个是只有个 root 节点,一个我自己都看不懂。

然后在项目路径下使用 npm start 启动项目,React 的默认端口是 3000,打开就可以看到页面了。

跨域问题

此时前端应用和后端服务都已经部署好了,在页面上发起请求尝试,在请求情况中可以看到请求失败了,状态为 CORS 错误,这是由于浏览器的同源策略导致的:

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。在同一个协议,域名,端口号下时,是为同源。

同源策略是浏览器的行为,是为了保护本地数据不被 JS 代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。

在上面,我们访问的是 3000 端口的前端应用,而前端应用去后端服务 8080 端口请求数据,因此触发了浏览器的跨域请求保护。

当然 CORS 问题是可以解决的,而且解决的办法有很多,我选择最简单的一种,在后端服务的 Controller 上添加注解 @CrossOrigin

@CrossOrigin
@RestController
@RequestMapping("/data")
public class DataController

这样这个 Controller 的请求就支持跨域访问了。但如果有很多地方或者整个项目都要支持跨域访问的话,还是使用 Config 配置的方式好一点。

posted @ 2023-04-23 17:21  Qirror  阅读(626)  评论(0)    收藏  举报
Live2D