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项目,然后按步骤补充几个关键文件:
- App.js,应用程序最大的组件;
- index.html,页面入口;
- index.js,将 App 渲染到页面上;
- 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';
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 配置的方式好一点。
标签:const,SpringBoot,分离,React,file,请求,页面 From: https://www.cnblogs.com/qiyuanc/p/Back12.html