ゴリゴリハマった💦
結論、画像ファイルをpublicフォルダ配下のuploadsフォルダに配置する際、画像ファイル名にランダムな文字列を付与していた。
さらに、ローカルサーバで画像を表示する際、さらに画像ファイル名にランダム文字列を付けていたため、①格納先の画像名とデータベースに保存している画像ファイル名に不一致が発生してしまい表示できなかった。
単なるプログラムミス...
なので、絶対に同じことを起こさないように記録しておきます。
問題になっていたコード
分かるだろうか。決定的によろしくないが2か所ある。
app/pages/api/upload.ts
'use server'
import { promises as fs } from "node:fs"
import { resolve } from "node:path"
import { revalidatePath } from "next/cache"
import { array, boolean } from "zod";
import { list } from "postcss";
import { getDB } from "@/app/lib/db";
//返却する値をタプル型配列に格納する(ユーザーID、イベントタイトル、イベント詳細、サムネイルパス)の順番
let eventInfoArray:[String,String,String,String];
export async function UploadFile(formData:FormData){
const file = formData.get("file") as File;
const userId = formData.get("userId");
const eventTitle = formData.get("eventTitle");
const eventDetail = formData.get("eventDetail");
//アップロードファイル情報を取得する
console.log(file);
//ユーザーIDを取得する
console.log(userId);
//イベントタイトルを取得する
console.log(eventTitle);
//イベント内容を取得する
console.log(eventDetail);
//ファイルのパス情報
let filePath = '';
if(file && file.size > 0){
const data = await file.arrayBuffer();
const buffer = Buffer.from(data);
filePath = resolve(
process.cwd(),
"./public/uploads", // "./uploads"
`${crypto.randomUUID()}.${file.name.split(".").pop()}`
);
await fs.writeFile(filePath,buffer);
//ファイル名を取得する
console.log("アップロードファイル名は、" + file.name);
//ファイルパスを取得する
console.log("修正後のファイルパスは:" + filePath);
//Next.jsプロジェクトの公開パス(public)配下に上書きする
filePath = `http://localhost:3000/uploads/` +`${crypto.randomUUID()}.${file.name.split(".").pop()}`;
console.log("修正後のこれの上書き後のファイルパスは:" + filePath);
}
revalidatePath("/file");
if(userId !=null && eventTitle != null && eventDetail !=null && file != null){
//返却値を配列に格納する
eventInfoArray = [userId?.toString(),eventTitle?.toString(),eventDetail?.toString(),filePath?.toString()];
console.log("配列情報は:" + eventInfoArray);
console.log("配列の最後尾は:" + eventInfoArray[3]);
//データベースへ登録する処理を実行
const registerationSuccess = await RegisterEventInfo(eventInfoArray);
console.log("イベントの登録に成功しました。");
return registerationSuccess;
}else{
console.log("イベントの登録に失敗しました。");
}
return false;
}
//データベースへ登録する処理
export async function RegisterEventInfo(array:any){
//データベース登録完了判定フラグ(完了:、true失敗:false)
let completeFlag = false;
let eventInfoArray = array;
console.log("渡された配列は、" + eventInfoArray);
//データベースへ接続する
const connection = await getDB();
try{
//登録する情報は1.ユーザID、2.イベントタイトル、3,イベント詳細、4,イベントのサムネイルパス
//イベントIDは自動連番のためクエリには記載しない
await connection.execute(`INSERT INTO eventInfo (userid,eventtitle,eventdetail,eventthumbnailpath) VALUES (?,?,?,?)`,
[eventInfoArray[0],eventInfoArray[1],eventInfoArray[2],eventInfoArray[3]]
)
console.log("イベント情報を登録しました。");
//データベース登録完了判定フラグを更新する
completeFlag = true;
//EvaluationFlagForEventRegister(completeFlag);
}catch(error){
console.log("イベント登録のエラーが発生しました。");
}finally{
connection.end();
}
//データベース登録完了判定フラグを更新する
//EvaluationFlagForEventRegister(completeFlag);
return completeFlag;
}
//データベース登録完了判定フラグを返却する処理
export async function EvaluationFlagForEventRegister(flag:boolean){
return flag;
}
それはここである...↓
①画像にランダムな文字列を生成するのは別に悪くはないが、文字列が長すぎる恐れや、画像が何を意味するのは一瞬で判断できないためできればわかりやすい文字列にしていきたい。
app/pages/api/upload.ts
filePath = resolve(
process.cwd(),
"./public/uploads", // "./uploads"
`${crypto.randomUUID()}.${file.name.split(".").pop()}`
);
上のコードを下記のように直す。
app/pages/api/upload.ts
filePath = resolve(
process.cwd(),
"./public/uploads", // "./uploads"
`${file.name}`
);
つぎが問題な箇所である。
app/pages/api/upload.ts
filePath = `http://localhost:3000/uploads/` +`${crypto.randomUUID()}.${file.name.split(".").pop()}`;
...なんと、さきほど生成した画像ファイルをさらにランダムな文字列に生成している。
そして、このパスをデータベースに格納している。
なるほど、だからブラウザからは見えなかったのか...💦
なので、こう直そう↓
app/pages/api/upload.ts
filePath = `http://localhost:3000/uploads/` +`${file.name}`;
そして、直した全体のコードがこちら↓
app/pages/api/upload.ts
'use server'
import { promises as fs } from "node:fs"
import { resolve } from "node:path"
import { revalidatePath } from "next/cache"
import { array, boolean } from "zod";
import { list } from "postcss";
import { getDB } from "@/app/lib/db";
//返却する値をタプル型配列に格納する(ユーザーID、イベントタイトル、イベント詳細、サムネイルパス)の順番
let eventInfoArray:[String,String,String,String];
export async function UploadFile(formData:FormData){
const file = formData.get("file") as File;
const userId = formData.get("userId");
const eventTitle = formData.get("eventTitle");
const eventDetail = formData.get("eventDetail");
//アップロードファイル情報を取得する
console.log(file);
//ユーザーIDを取得する
console.log(userId);
//イベントタイトルを取得する
console.log(eventTitle);
//イベント内容を取得する
console.log(eventDetail);
//ファイルのパス情報
let filePath = '';
if(file && file.size > 0){
const data = await file.arrayBuffer();
const buffer = Buffer.from(data);
filePath = resolve(
process.cwd(),
"./public/uploads", // "./uploads"
`${file.name}`
);
await fs.writeFile(filePath,buffer);
//ファイル名を取得する
console.log("アップロードファイル名は、" + file.name);
//ファイルパスを取得する
console.log("修正後のファイルパスは:" + filePath);
//Next.jsプロジェクトの公開パス(public)配下に上書きする
filePath = `http://localhost:3000/uploads/` +`${file.name}`;
console.log("修正後のこれの上書き後のファイルパスは:" + filePath);
}
revalidatePath("/file");
if(userId !=null && eventTitle != null && eventDetail !=null && file != null){
//返却値を配列に格納する
eventInfoArray = [userId?.toString(),eventTitle?.toString(),eventDetail?.toString(),filePath?.toString()];
console.log("配列情報は:" + eventInfoArray);
console.log("配列の最後尾は:" + eventInfoArray[3]);
//データベースへ登録する処理を実行
const registerationSuccess = await RegisterEventInfo(eventInfoArray);
console.log("イベントの登録に成功しました。");
return registerationSuccess;
}else{
console.log("イベントの登録に失敗しました。");
}
return false;
}
//データベースへ登録する処理
export async function RegisterEventInfo(array:any){
//データベース登録完了判定フラグ(完了:、true失敗:false)
let completeFlag = false;
let eventInfoArray = array;
console.log("渡された配列は、" + eventInfoArray);
//データベースへ接続する
const connection = await getDB();
try{
//登録する情報は1.ユーザID、2.イベントタイトル、3,イベント詳細、4,イベントのサムネイルパス
//イベントIDは自動連番のためクエリには記載しない
await connection.execute(`INSERT INTO eventInfo (userid,eventtitle,eventdetail,eventthumbnailpath) VALUES (?,?,?,?)`,
[eventInfoArray[0],eventInfoArray[1],eventInfoArray[2],eventInfoArray[3]]
)
console.log("イベント情報を登録しました。");
//データベース登録完了判定フラグを更新する
completeFlag = true;
//EvaluationFlagForEventRegister(completeFlag);
}catch(error){
console.log("イベント登録のエラーが発生しました。");
}finally{
connection.end();
}
//データベース登録完了判定フラグを更新する
//EvaluationFlagForEventRegister(completeFlag);
return completeFlag;
}
//データベース登録完了判定フラグを返却する処理
export async function EvaluationFlagForEventRegister(flag:boolean){
return flag;
}
以上です。