1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

React + Spring Boot での画像投稿

Last updated at Posted at 2022-01-24

#はじめに
ReactとSpring Boot + Chakra UIでアプリケーション開発を行おうとしており、
その過程で画像投稿機能を組み込む予定なため学んだことを備忘録として記載します。

#React

NewUser.tsx
return (
    <>
      <Wrap justify="center" mt={5}>
      <Box 
      w="100vh"
      h="750px"
      bg="white"
      borderRadius="10px"
      shadow="md" p={4}
      _hover={{cursor: "pointer", opacity: 0.8}}
    >
      <Stack textAlign="center" spacing={5} p={4}>
        <FormControl>
          <FormLabel>名前</FormLabel>
          <Input value={name} onChange={onChangeName}/ >
        </FormControl>
        <FormControl>
          <FormLabel>メールアドレス</FormLabel>
          <Input value={email} onChange={onChangeEmail}/>
        </FormControl>
        <FormControl>
          <FormLabel>TEL</FormLabel>
          <Input value={phone} onChange={onChangePhone}/>
        </FormControl>
        <FormControl>
          <FormLabel>ユーザーネーム</FormLabel>
          <Input value={username} onChange={onChangeUsername}/>
        </FormControl>
        <FormControl>
          <FormLabel>概要</FormLabel>
          <Input value={description} onChange={onChangeDescription}/>
        </FormControl>
        <FormControl>
          <FormLabel>画像</FormLabel>
          <Input type="file" accept="image/*,.png,.jpg,.jpeg" onChange={(e: React.ChangeEvent<HTMLInputElement>) => getImage(e)}/>
        </FormControl>
        <FormControl>
          <FormLabel>パスワード</FormLabel>
          <InputGroup size='md'>
            <Input type={show ? 'text' : 'password'} value={password} onChange={onChangePassword}/>
            <InputRightElement width='4.5rem'>
              <Button h='1.75rem' size='sm' onClick={clickShow} >
                {show ? 'Hide' : 'Show'}
              </Button>
            </InputRightElement>
          </InputGroup>
        </FormControl>
        <Button borderRadius={10} bg="teal.300" onClick={onClickUserPost}>登録</Button>
      </Stack>
    </Box>
    </Wrap>
    </>
  )

HTMLの部分はこんな感じ

#画像投稿機能

NewUser.tsx
const [images, setImages] = useState<File>();

const getImage = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    if(!e.target.files) return
    const img: File = e.target.files[0]
    setImages(img)
  },[])

e.target.files[0]でFile型にしたのを変数に入れ、
Stateに格納します。

#Spring側にpost

NewUser.tsx
const onClickUserPost = () => {
    const data = new FormData()
    data.append('file',images)

    const user = {
      name : name,
      email: email,
      phone: phone,
      username: username,
      description: description,
      password: password
    }

    data.append('user',new Blob([JSON.stringify(user)],{type : 'application/json'}))
    console.log(data)
    axios.post("http://localhost:8080/api/v1/users_manegement/", data)
    .then( () => {
      history.push("/");
    }).catch(() => alert("失敗しました!"));
  }

ここで大事なのはFormData()です。
FormDataを詰め込むとmultipart/form-dataとして送れるとのこと。
単純な文字列データ以外も送れるとのことで重宝しそう。
appendする際はキー名とvalueを書く

文字列はJSON文字列に変換後、バイナリデータとしてFormDataに格納しAxiosでpostをすれば終わりです。

import時のコマンド
npm install --save form-data

#Spring Boot

UserController.java
@Operation(summary = "ユーザーを登録します")
	@PostMapping("/")
	public User insert(
            @RequestPart("user") User user,
			@RequestPart("file") MultipartFile file)
            throws IOException {
		
		
		return servise.insert(user, file);
	}

@RequestPartでReact側で指定したキー名と受け取るvalueを書けばバイナリーデータを受信できます。

#Base64に変換

UserServise.java
package dex.itboot.rest.servise;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Base64;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import dex.itboot.rest.form.UserForm;
import dex.itboot.rest.model.User;
import dex.itboot.rest.repository.UserRepository;


@Service
public class UserServise {

	@Autowired
	private UserRepository repository;
	
	public User insert(User user, MultipartFile file) throws IOException {
		
		String fileEntension = null;
		
		try {
			fileEntension = getEntension(file.getOriginalFilename());
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		String base64FileString = Base64.getEncoder().encodeToString(file.getBytes());
		if("jpg".equals(fileEntension)) {
			base64FileString = "data:image/jpeg;base64," + base64FileString;
		} else if("png".equals(fileEntension)) {
			base64FileString = "data:image/png;base64," + base64FileString;
		}
		
		user.setImage(base64FileString);
		
		return repository.save(user);
		
	}
	
	private String getEntension(String fileName) throws Exception {
		if(fileName == null) {
			throw new FileNotFoundException();
		}
		
		int point = fileName.lastIndexOf(".");
		if (point == -1) {
			throw new FileNotFoundException();
		}
		return fileName.substring(point + 1);
		
	}
}

受け取った画像をBase64(テキストデータ)に変換してDBにINSERTすれば完了。
これで完了!!

#まとめ
画像データをサーバー側に送るには

今回書いたmultipart/form-dataで送る方法と
application/jsonで送る方法があるとのこと。

ただJSONで送ると送信データが増えるとのこと
それぞれメリット・デメリットがあるのでもっと学ばなきゃな...

あとAxiosで送る関数もカスタムフック化したりすると見やすくなるのかなと思います!

以上です!

###参考記事
https://qiita.com/harumaxy/items/035ee46c82e8211d831c

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?