1、项目结构
项目是基于webpack4, 参考 创建基本的webpack4.x项目
2、页面效果
初始化效果
添加功能
通过id删除
更新功能
3、代码
package.json
{ "name": "react-helloworld", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack-dev-server --open --port 3000 --hot --host 127.0.0.1" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "babel-core": "^6.26.3", "babel-loader": "^7.1.5", "babel-plugin-transform-runtime": "^6.23.0", "babel-preset-env": "^1.7.0", "babel-preset-react": "^6.24.1", "babel-preset-stage-0": "^6.24.1", "html-webpack-plugin": "^3.2.0", "webpack": "^4.41.2", "webpack-cli": "^3.3.10", "webpack-dev-server": "^3.9.0" }, "dependencies": { "prop-types": "^15.7.2", "react": "^16.12.0", "react-dom": "^16.12.0" } }
webpack.config.js
var path = require('path') // 导入在内存中自动生成index页面的插件 const HtmlWebPackPlugin = require('html-webpack-plugin') const htmlPlugin = new HtmlWebPackPlugin({ template: path.join(__dirname, './src/index.html'), filename: 'index.html' // 生成的内存中首页的名称 }); module.exports = { mode: 'development', plugins: [ htmlPlugin ], module: { rules:[ { test:/\.js|jsx$/, use: ['babel-loader'], exclude: /node_modules/ } ] }, resolve: { extensions: ['.js', '.jsx', '.json'], // 这些文件的后缀可以省略 alias: { '@': path.join(__dirname, './src') } } }
.babelrc
{ "presets": ["env", "stage-0", "react"], "plugins": ["transform-runtime"] }
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>主页</title> <!-- <script src="../dist/main.js"></script> --> <!-- <script src="/main.js"></script> --> </head> <body> 首页 <div id="root"></div> </body> </html>
index.js
import React from 'react' import ReactDOM from 'react-dom' import App from './components/app/App.jsx' ReactDOM.render(<App />, document.getElementById('root'))
组件App.jsx
import React from 'react' import UserAdd from '../user-add/UserAdd.jsx' import UserList from '../user-list/UserList.jsx' export default class App extends React.Component { constructor() { super() this.state = { title: '用户模块', userList: [ { id: 1, name: '张三1', age: 10 }, { id: 2, name: '张三2', age: 20 }, { id: 3, name: '张三3', age: 30 } ] } this.addUser = this.addUser.bind(this) this.delUser = this.delUser.bind(this) this.editUser = this.editUser.bind(this) } addUser(obj) { const { userList } = this.state const len = userList.length const id = userList[len - 1].id + 1 obj.id = id console.log(JSON.stringify(obj)) userList.push(obj) this.setState({ userList }) } delUser(id) { const { userList } = this.state // 删除指定id的记录 console.log('删除指定id=' + id + '的记录') for (var i = 0; i < userList.length; i++) { if (userList[i].id == id) { userList.splice(i, 1); // 删除起始下标为id-1,长度为1的元素 } } this.setState({ userList }) } editUser(obj) { const {id} = obj const { userList } = this.state console.log('修改指定id=' + id + '的记录. 数据对象:' + JSON.stringify(obj)) for (var i = 0; i < userList.length; i++) { if (userList[i].id == id) { userList[i].name = obj.name userList[i].age = obj.age } } this.setState({ userList }) } render() { return ( <div> <h2>{this.state.title}</h2> <UserAdd addUser={this.addUser} /> <UserList userList={this.state.userList} delUser={this.delUser} editUser={this.editUser}/> </div> ) } }
组件UserAdd.jsx
import React from 'react' import PropTypes from 'prop-types' export default class UserAdd extends React.Component { constructor() { super() this.state = { msg: 'hello react', id: 'a', name: '', age: '' } // this.submitHandler = this.submitHandler.bind(this) this.nameInputChangeHandler = this.nameInputChangeHandler.bind(this) this.ageInputChangeHandler = this.ageInputChangeHandler.bind(this) } render() { return ( <div> <h3>添加用户</h3> <form action="#" method="post"> <input type="text" placeholder="请输入用户名" name="name" value={this.state.name} onChange={this.nameInputChangeHandler} /> <br /><br /> <input type="text" placeholder="请输入年龄" name="age" value={this.state.age} onChange={this.ageInputChangeHandler} /> <br /><br /> <input type="button" value="添加" onClick={() => this.submitHandler()}/> </form> </div> ) } submitHandler = () => { const {name, age} = this.state console.log(name) console.log(age) const user = {name, age} this.props.addUser(user) // event.preventDefault() } nameInputChangeHandler(event) { // console.log(event.target.value) const name = event.target.value this.setState({ name }) } ageInputChangeHandler(event) { const age = event.target.value this.setState({ age }) } } // 指定组件props属性的类型和必要性 UserAdd.propTypes = { addUser: PropTypes.func.isRequired }
组件UserList.jsx
import React from 'react' import PropTypes from 'prop-types' import UserItem from '../user-item/UserItem.jsx' import './UserList.css' export default class UserList extends React.Component { render() { return ( <div> <h3>用户列表展示</h3> <table border="1" cellPadding="0" cellSpacing="0" width="500" height="150"> <thead align="center"> <tr> <td>ID</td> <td>姓名</td> <td>年龄</td> <td>操作</td> </tr> </thead> <tbody align="center"> {this.props.userList.map(user => <UserItem key={user.id} user={user} delUser={this.props.delUser} editUser={this.props.editUser}/>)} </tbody> </table> </div> ) } } // 指定组件props属性的类型和必要性 UserList.propTypes = { userList: PropTypes.array.isRequired, delUser: PropTypes.func.isRequired, editUser: PropTypes.func.isRequired }
UserItem.jsx
import React from 'react' import PropTypes from 'prop-types' export default class UserList extends React.Component { constructor() { super() this.state = { id: '', name: '', age: '' } this.delClickHandler = this.delClickHandler.bind(this) this.nameInputChangeHandler = this.nameInputChangeHandler.bind(this) this.ageInputChangeHandler = this.ageInputChangeHandler.bind(this) } componentDidMount() { const {id, name, age} = this.props.user // console.log(id + " " + name + " " + age) this.setState({id, name, age}) } render() { return ( <tr> <td>{this.props.user.id}</td> <td><input type="text" value={this.state.name} style={{width:'50%',textAlign:'center'}} onChange={this.nameInputChangeHandler}/></td> <td><input type="text" value={this.state.age} style={{width:'50%',textAlign:'center'}} onChange={this.ageInputChangeHandler}/></td> <td><a href="#" onClick={() => this.delClickHandler(this.state.id)}>删除</a> <a href="#" onClick={() => this.editClickHandler()}>修改</a></td> </tr> ) } delClickHandler(id) { this.props.delUser(id) } editClickHandler() { const {id, name, age} = this.state const obj = {id, name, age} this.props.editUser(obj) } nameInputChangeHandler(event) { const name = event.target.value console.log("input onchange事件,获取输入框name的当前值:" + name) this.setState({ name }) } ageInputChangeHandler(event) { const age = event.target.value console.log("input onchange事件,获取输入框age的当前值:" + age) this.setState({ age }) } } // 指定组件props属性的类型和必要性 UserList.propTypes = { user: PropTypes.object.isRequired, delUser: PropTypes.func.isRequired, editUser: PropTypes.func.isRequired }
4、数据交互改为与数据库交互
修改App.jsx
import React from 'react' import UserAdd from '../user-add/UserAdd.jsx' import UserList from '../user-list/UserList.jsx' import Axios from "axios"; import Qs from 'qs' export default class App extends React.Component { constructor() { super() this.state = { title: '用户模块', userList: [ // { id: 1, name: '张三1', age: 10 }, // { id: 2, name: '张三2', age: 20 }, // { id: 3, name: '张三3', age: 30 } ] } this.addUser = this.addUser.bind(this) this.delUser = this.delUser.bind(this) this.editUser = this.editUser.bind(this) } componentDidMount() { Axios.get('http://localhost:4000/react-db-crud/user').then(res => { console.log(this.state.userList) const userList = res.data console.log(userList) this.setState({ userList }, function () { console.log("componentDidMount生命周期函数调用this.setState()完成") console.log(this.state.userList) }) }) } addUser(obj) { // obj包含name和age属性 // console.log(Qs.stringify(obj)) // name=22&age=22 // 插入数据库 Axios.post('http://localhost:4000/react-db-crud/user', Qs.stringify(obj), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).then(res => { console.log(res) console.log("res.data.code=" + res.data.code) if (res.data.code == 0) { //console.log(res.data.data) this.setState({ userList: res.data.data }) } }) } delUser(id) { Axios.delete('http://localhost:4000/react-db-crud/user/' + id).then(res => { if (res.data.code == 0) { //console.log(res.data.data) this.setState({ userList: res.data.data }) } }) } editUser(obj) { // obj包含id、name和age属性 const { id } = obj Axios.put('http://localhost:4000/react-db-crud/user/' + id, Qs.stringify(obj)).then(res => { if (res.data.code == 0) { //console.log(res.data.data) this.setState({ userList: res.data.data }) } }) } render() { return ( <div> <h2>{this.state.title}</h2> <UserAdd addUser={this.addUser} /> <UserList userList={this.state.userList} delUser={this.delUser} editUser={this.editUser} /> </div> ) } }
5、API接口
application.properties
server.port=4000 server.servlet.context-path=/react-db-crud #datasource spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=123456 spring.datasource.tomcat.min-idle=5 ##################### MyBatis相关配置 [start] ##################### #MyBatis映射文件 mybatis.mapper-locations=classpath:com/oy/mapping/*.xml #扫描生成实体的别名,需要和注解@Alias联合使用 mybatis.type-aliases-package=com.oy.model #MyBatis配置文件,当你的配置比较复杂的时候,可 以使用 #mybatis.config-location= #级联延迟加载。true:开启延迟加载 mybatis.configuration.lazy-loading-enabled=true #积极的懒加载。false:按需加载 mybatis.configuration.aggressive-lazy-loading=false ##################### MyBatis相关配置 [end] #####################
MainApplication.java
@MapperScan("com.oy.dao") @SpringBootApplication public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }
跨域配置CorsConfig
@Configuration public class CorsConfig { private CorsConfiguration buildConfig() { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigin("*"); // 允许任何域名 corsConfiguration.addAllowedHeader("*"); // 允许任何头 corsConfiguration.addAllowedMethod("*"); // 允许任何方法 return corsConfiguration; } @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", buildConfig()); // 注册 return new CorsFilter(source); } }
UserController.java
@RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @GetMapping("") public Object findAll() { List<User> userList = userService.findAll(); return userList; } @PostMapping("") public Object addUser(User user) { System.out.println(user); userService.add(user); JSONObject res = new JSONObject(); res.put("code", 0); res.put("msg", "insert succ"); res.put("data", userService.findAll()); return res; } @DeleteMapping("/{id}") public Object delUser(@PathVariable Integer id) { userService.deleteById(id); JSONObject res = new JSONObject(); res.put("code", 0); res.put("msg", "delete succ"); res.put("data", userService.findAll()); return res; } @PutMapping("/{id}") public Object editUser(@PathVariable Integer id, String name, Integer age) { User user = new User(); user.setId(id); user.setName(name); user.setAge(age); userService.updateById(user); JSONObject res = new JSONObject(); res.put("code", 0); res.put("msg", "edit succ"); res.put("data", userService.findAll()); return res; } }