mysql - 我正在尝试显示我用 multer 上传到后端的图像

标签 mysql node.js reactjs multer

我正在使用 multer 从我的 react 客户端上传图像。所有图像都已存储,只是没有显示。图像正在存储,但未在 react 中显示。设置为不显示状态。我可以在后端的图像文件夹中看到它们,所以我知道 multer 正在工作。

这是我的 react 组件

class AddNewDish extends Component {
    constructor(props){
        super(props)
        this.state = {
            name: '',
            imageUrl: '',
            description: ''

        }
    }



    createDishHandler = (event) => {
        event.preventDefault()
        const fd = new FormData();
        fd.append('name', this.state.name)
        fd.append('imageUrl', this.state.imageUrl, this.state.imageUrl.name)
        fd.append('description', this.state.description)
        axios.post('http://localhost:8080/add-new-dish', fd,)
            .then(res => {
                console.log(res, 'res')
            })
        this.props.history.push('/')
    }


    onChange = (e) => {
        switch(e.target.name) {

            case 'imageUrl':
                this.setState({imageUrl: e.target.files[0]});
                break;
            default:
                this.setState({[e.target.name]: e.target.value})
        }
        console.log(e)
    }



    render () {
        console.log(this.state.imageUrl, 'in imgUrl')
        return (
            <div>
             <form onSubmit={this.createDishHandler}> 
                <input
                    label='Name'
                    onChange={this.onChange}
                    name='name'
                    type='text'
                    placeholder='Enter Dish Name'
                    value={this.state.name}
                />

                < input
                    label='Dish Image'
                    onChange={this.onChange}
                    name='imageUrl'
                    type='file'
                    placeholder='Enter Dish Image'
                    // value={this.state.imageUrl}
                />

                 <input
                    label='Description'
                    onChange={this.onChange}
                    name='description'
                    placeholder='Enter Dish Description'
                    type='text'
                    value={this.state.description}
                />
                <img src={this.state.imageUrl}/>
                 <button>Submit Dish</button> 
             </form> 
            </div>
        )
    }
};

export default AddNewDish

一个后端


const multer = require('multer');

const fileStorage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, 'public')
    },
    filename: (req, file, cb) => {
        cb(null, new Date().toISOString() + '-' + path.extname(file.originalname))
    }
});

const fileFilter = (req, file, cb) => {
    if(
        file.mimetype === 'image/png' ||
        file.mimetype === 'image/jpg' || 
        file.mimetype === 'image/jpeg'
        ) {
            cb(null, true)
    } else {
        cd(null, false)
    }
}
exports.upload = multer({

        storage: fileStorage, 
        fileFilter: fileFilter
    })
        .single('imageUrl')

这就是我如何称呼我的路线

exports.postADish = async  ( req, res,) => {
    console.log(req.file, 'in req.file')

    try {
        const { name,  description } = req.body;
        const imageUrl = req.file.path

            const newDish = await dish.postNewDish({name, description, imageUrl})
            res.status(201).json(`new dish added`)

    } catch (err) {
        res.status(500).json(`Error posting dish`)
        console.log(err)
    }
};

我如何使用上传中间件

router.post('/add-new-dish', dishController.upload, dishController.postADish);

公开文件夹

app.use('/public', express.static('public'))

这就是我尝试在前端显示索引路由中的图像的方式

class App extends Component {
  constructor () {
    super()
    this.state = {
      data: []

    }

  }

    componentDidMount()  {
      axios
        .get(`http://localhost:8080/`)
        .then(res => {
          console.log(res, 'response')
          this.setState({
            data: res.data.dishData
          })
        })
        .catch(err => {
          console.log(err)
        })
  }


  render() {
   console.log(this.state.data)
    return (
      <div className="App">
        <Nav

         <Route
            exact path ='/'
            render={props =>
              <Home 
                {...props}
                dishes={this.state.data}

              />
            }
          />

我的状态是这样的

{id: 7, name: "test dish", imageUrl: "public/2019-04-20T22:52:09.900Z-20190411_112505.jpg", description: "test description"}

我正在取回 imageUrl 并在 home 组件中使用它,如下所示

const Home = (props) => {
    return (
        <DishWrapper>
            <DishContent>
           {props.dishes.map(dish => {
               console.log(dish, 'in dish')
               return (

                   <Dish key={dish.id}>
                        <h3>{dish.name}</h3>
                        <img src={ `public/${dish.imageUrl}`} alt={dish.name}/>
                        <h5>{dish.description}</h5>
                   </Dish>

               )
           })}
            </DishContent>
        </DishWrapper>
    )
};

export default Home

在后端我的获取看起来像这样

exports.getDishes = async (req, res) => {
    try {
        const dishData = await dish.getDishes()
        if(!dishData) {
            res.status(404).json(`No dishes available at this time`)
        } else {
            res.status(200).json({
                dishData, 

            })
        }
    } catch (err) {
        res.status(500)
        console.log(err)
    }
};

最佳答案

因此,要在上传之前查看图像,您需要首先使用 FileReader这是一个 javascript 对象,可让 Web 应用程序异步读取文件内容。这将为您提供图像的 Base64 版本,您可以将其添加到图像 src 中。因此,您可以在 onChange 函数中执行此操作,它看起来如下所示:

onChange = (e) => {
    switch(e.target.name) {

        case 'imageUrl':
            const file = e.target.files[0];
            const reader = new FileReader();
            reader.onload = () => {
                this.setState({
                    imageUrl: file,
                    imgBase64: reader.result
                })
            };
            reader.readAsDataURL(file);
            break;
        default:
            this.setState({[e.target.name]: e.target.value})
    }
}

在此示例中,我将 imgBase64 键添加到状态,并向其中添加 base64 值,但您可以使用您喜欢的任何名称,只需确保将其添加到您的状态对象即可。

然后要查看它,您可以使用该值作为图像 src,如下所示:

<img src={this.state.imgBase64}/>

之后,当您将图像提交到 multer 时,您需要返回图像的文件名,以便您可以在上传图像后访问它,因此在您的 route ,因为您在记录时似乎获得了正确的文件名,因此您可以返回它到您的 axios 调用并在之后使用它。因此,在您的 route ,只需发回一个 json 对象并使用它。因此,不要发送 res.status(201).json(new菜肴添加) ,而是发送如下内容:

res.status(201).json({
  msg: 'new dish added',
  imageUrl: req.file.filename
})

然后你的 axios 调用将收到这个 json 对象,你可以像这样在前端访问:

createDishHandler = (event) => {
    event.preventDefault()
    const fd = new FormData();
    fd.append('name', this.state.name)
    fd.append('imageUrl', this.state.imageUrl, this.state.imageUrl.name)
    fd.append('description', this.state.description)
    axios.post('http://localhost:8080/add-new-dish', fd,)
        .then(res => {
            //you can set your res.data.imageUrl to your state here to use it
            console.log('Success Message: ' + res.data.msg + ' - Image File Name: ' + res.data.imageUrl)
        })
    this.props.history.push('/')
}

但是在上面的函数中,我看到您在上传时推送了不同的页面。因此,如果您推送到不同的页面,那么您显然不会再使用此状态,因此您可能需要从新页面的数据库中检索它。

无论如何,我希望这对您有所帮助,如果您有任何疑问,请告诉我。

附注我只是想让您知道您可能想要使用 Date.now() + path.extname(file.originalname) 而不是 new Date().toISOString() + '-' + path.extname(file.originalname) 在你的 multer upload 中,它看起来更干净一点,没有所有的冒号和破折号,但这不是必需的。

编辑:

因此,如果您要使用 Express 提供静态文件夹,那么就像我在下面之前的评论中所说的那样,您将必须使用绝对 URL 来访问您的内容。 React 无法访问客户端中公共(public)文件夹之外的相对路径的任何内容。因此,如果在您的后端根目录中您将有一个名为 images 的文件夹,那么在 multer 中您可以将目标设置为 'images' 并使用express,您将提供静态文件夹 app.use( express.static('images')) 并使用您的图像访问它,您需要使用绝对网址

<img src={ `http://localhost:8080/${imageUrl}`} alt={dish.name}/>

关于mysql - 我正在尝试显示我用 multer 上传到后端的图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55769505/

相关文章:

javascript - onMouseOver 和 onMouseOut 切换输入和 div,并更改 div 的值

c# - 获取 Datagrid WPF 列上的选定项目并通过 Linq 查找它

php - 如何在php中从一个sql表中减去另一个表中的数据?

php - 使用 $_FILES 更新图像时出错

angularjs - 使用 Node.js 和 Angular 更新数据库

javascript - React服务器端渲染,在开发环境中生成html

c++ - 通过C++访问MySQL

angularjs - prerender.io aws 弹性 beanstalk 部署

node.js - 异步并行 HTTP 请求

node.js - NPM/Webpack 无法正确加载 GSAP TimelineLite