
Member.jsx(React)
export function MemberEdit() {
const [member, setMember] = useState(null);
const [passwordCheck, setPasswordCheck] = useState("");
const [oldPassword, setOldPassword] = useState(""); //๊ธฐ์กด ํจ์ค์๋
const [oldNickName, setOldNickName] = useState(""); // ๊ธฐ์กด ๋๋ค์
const [isCheckedNickName, setIsCheckedNickName] = useState(true);
const { id } = useParams();
const toast = useToast();
const navigate = useNavigate();
const { isOpen, onClose, onOpen } = useDisclosure();
useEffect(() => {
axios
.get(`/api/member/${id}`)
.then((response) => {
const member1 = response.data;
setMember({ ...member1, password: "" });
setOldNickName(member1.nickName);
})
.catch((err) => {
toast({
status: "error",
description: "ํด๋น ํ์์ด ์์ต๋๋ค.",
position: "top-right",
duration: 1000,
});
navigate("/");
});
}, []);
function handleClickSave() {
axios
.put(`/api/member/modify`, { ...member, oldPassword })
.then(() => {
toast({
status: "success",
description: `${member.id}๋ฒ ํ์์ด ์์ ๋์์ต๋๋ค.`,
position: "top-right",
});
navigate(`/member/${member.id}`);
})
.catch((err) => {
if (err.response.status === 400) {
toast({
status: "error",
description: `ํ์ ์ ๋ณด๊ฐ ์์ ๋์ง ์์์ต๋๋ค. ์์ฑํ ๋ด์ฉ์ ํ์ธํด์ฃผ์ธ์.`,
position: "top-right",
});
}
})
.finally(() => {
onClose();
setOldPassword("");
});
}
function handleCheckNickName() {
axios
.get(`/api/member/check?nickName=${member.nickName}`)
.then((res) => {
toast({
status: "warning",
description: "์ค๋ณต๋ ๋๋ค์์
๋๋ค.",
position: "top",
duration: 1000,
});
})
.catch((err) => {
if (err.response.status === 404) {
toast({
status: "info",
description: "์ฌ์ฉํ ์ ์๋ ๋๋ค์์
๋๋ค.",
position: "top",
duration: 1000,
});
setIsCheckedNickName(true); // ์ค๋ณตํ์ธํ๊ณ ์ฌ์ฉํ ์ ์์ผ๋ฉด true, ์
๋ ฅ์ ์์ํ๋ฉด false
}
})
.finally();
}
if (member == null) {
return <Spinner />;
}
let isDisableNickNameCheckButton = false;
if (member.nickName === oldNickName) {
isDisableNickNameCheckButton = true;
}
if (member.nickName.trim().length === 0) {
isDisableNickNameCheckButton = true;
}
if (isCheckedNickName) {
isDisableNickNameCheckButton = true;
}
let isDisableSaveButton = false;
if (member.password !== passwordCheck) {
isDisableSaveButton = true;
}
if (member.nickName.trim().length === 0) {
isDisableSaveButton = true;
}
if (!isCheckedNickName) {
isDisableSaveButton = true;
}
return (
<Box>
<Box>{member.id}๋ฒ ํ์</Box>
<Box>
<FormControl>
<FormLabel>์ด๋ฉ์ผ</FormLabel>
<Input value={member.email} readOnly />
</FormControl>
</Box>
<Box>
<FormControl>
<FormLabel>๋น๋ฐ๋ฒํธ</FormLabel>
<Input
defaultValue={member.password}
placeholder={"์ํธ๋ฅผ ๋ณ๊ฒฝํ๋ ค๋ฉด ์
๋ ฅํ์ธ์."}
onChange={(e) => setMember({ ...member, password: e.target.value })}
/>
<FormHelperText color={"red"}>
์
๋ ฅํ์ง ์์ผ๋ฉด ๊ธฐ์กด ์ํธ๋ฅผ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค.
</FormHelperText>
</FormControl>
</Box>
<Box>
<FormControl>
<FormLabel>๋น๋ฐ๋ฒํธ ํ์ธ</FormLabel>
<Input onChange={(e) => setPasswordCheck(e.target.value)} />
{member.password === passwordCheck || (
<FormHelperText color={"red"}>
๋น๋ฐ๋ฒํธ๊ฐ ์ผ์งํ์ง ์์ต๋๋ค.
</FormHelperText>
)}
</FormControl>
</Box>
<Box>
<FormControl>
<FormLabel>๋๋ค์</FormLabel>
<InputGroup>
<Input
onChange={(e) => {
const newNickName = e.target.value.trim();
setMember({ ...member, nickName: newNickName });
setIsCheckedNickName(newNickName === oldNickName); // ๊ธฐ์กด ๋๋ค์๊ณผ ์๋ก์ด ๋๋ค์์ด ๊ฐ์ง ์์๋,์
๋ ฅ์ ์์ํ ๋ ํ์ฑํ
}}
value={member.nickName}
/>
<InputRightElement w={"100px"} mr={1}>
<Button
isDisabled={isDisableNickNameCheckButton}
onClick={handleCheckNickName}
colorScheme={"green"}
>
์ค๋ณต ํ์ธ
</Button>
</InputRightElement>
</InputGroup>
{isDisableNickNameCheckButton || (
<FormHelperText color={"red"}>
๋๋ค์ ์ค๋ณต ํ์ธ ํด์ผ ํฉ๋๋ค.
</FormHelperText>
)}
</FormControl>
</Box>
<Box>
<Button
isDisabled={isDisableSaveButton}
colorScheme={"blue"}
onClick={onOpen}
>
์ ์ฅ
</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>
<FontAwesomeIcon icon={faTriangleExclamation} />
๊ธฐ์กด ํจ์ค์๋ ํ์ธ
</ModalHeader>
<ModalBody>
<FormControl>
<FormLabel>๊ธฐ์กด ํจ์ค์๋</FormLabel>
<Input onChange={(e) => setOldPassword(e.target.value)} />
</FormControl>
</ModalBody>
<ModalFooter>
<Button onClick={handleClickSave} colorScheme={"blue"}>
ํ์ธ
</Button>
<Button onClick={onClose}>์ทจ์</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Box>
</Box>
);
}
/api/member/${id} ๊ฒฝ๋ก๋ก GET ์์ฒญ์ ํด์ member ๊ฐ์ฒด๋ฅผ ๋ฐ์์ค๋๋ฐ ๊ทธ ๋ member ๊ฐ์ฒด์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋น ๊ฐ์ผ๋ก ๊ฐ์ ธ์ต๋๋ค. ํ๋ฉด์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด <Input/> ํ๊ทธ์์ defaultValue์์ฑ์ ์ฌ์ฉํ์ฌ ์ด๋ฏธ ์ ์ฅ๋์ด ์๋ ๊ฐ(์ด๊ธฐ๊ฐ)์ ๊ฐ์ ธ์ฌ ์ ์๋๋ก ์ค์ ํด์ค๋๋ค./api/member/modify ๊ฒฝ๋ก๋ก PUT ์์ฒญ์ ํด์ member ๊ฐ์ฒด๋ฅผ ์์ฒญ ๋ณธ๋ฌธ์ ๋ด์ ๋ณด๋
๋๋ค. MemberController.java
@PutMapping("modify")
public ResponseEntity modify(@RequestBody Member member) {
if (service.hasAccessModify(member)) {
service.modify(member);
return ResponseEntity.ok().build();
} else {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
}
MemberService.java
public void modify(Member member) {
if (member.getPassword() != null && member.getPassword().trim().length() > 0) {
// ํจ์ค์๋๊ฐ ์
๋ ฅ(๋ณ๊ฒฝ)๋์์ผ๋ ๋ฐ๊พธ๊ธฐ
member.setPassword(passwordEncoder.encode(member.getPassword()));
} else {
// ํจ์ค์๋๊ฐ ์
๋ ฅ์ด ์๋์ผ๋ฉด ๊ธฐ์กด ๊ฐ์ผ๋ก ์ ์ง
Member dbMember = mapper.selectById(member.getId());
member.setPassword(dbMember.getPassword());
}
mapper.update(member);
}
public boolean hasAccessModify(Member member) {
Member dbMember = mapper.selectById(member.getId());
if (dbMember == null) {
return false;
}
if (!passwordEncoder.matches(member.getOldPassword(), dbMember.getPassword())) {
return false;
}
return true;
}
modify : ํจ์ค์๋๋ฅผ ํด๋ผ์ด์ธํธ์๊ฒ ๋น ๊ฐ์ผ๋ก ๋ณด๋ด์ฃผ์๊ธฐ ๋๋ฌธ์ ํจ์ค์๋๋ฅผ ๋ณ๊ฒฝํ์ง ์์ผ๋ฉด mapper์์ Update๋ฅผ ํ ์ ์์ต๋๋ค. ๊ทธ๋์ ํจ์ค์๋๋ฅผ ์
๋ ฅํ๋ค๋ฉด encoding ํด์ ๋ฃ์ด์ฃผ๊ณ ํจ์ค์๋๊ฐ ์
๋ ฅ๋์ง ์์๋ค๋ฉด ๊ธฐ์กด์ ์ ์ฅ๋์ด ์๋(DB) ํ์์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ ์งํด์ค๋๋ค. hasAccessModify() : ๋ฉํผ์์ DB์ ํ์ ID๋ฅผ ์กฐํํด์ ๊ทธ ์์ด๋์ ํด๋นํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ ๋น๋ฐ๋ฒํธ(dbMember.getPassword())์ ๊ธฐ์กด ๋น๋ฐ๋ฒํธ(member.getOldPassword())๊ฐ ์ผ์นํ๋์ง ํ์ธํ๊ณ encoding์ ํด์ค๋๋ค.MemberMapper.java
@Update("UPDATE member SET password=#{password}, nick_name=#{nickName} WHERE id=#{id}")
int update(Member member);
<Box>
<FormControl>
<FormLabel>๋๋ค์</FormLabel>
<InputGroup>
<Input
onChange={(e) => {
const newNickName = e.target.value.trim();
setMember({ ...member, nickName: newNickName });
setIsCheckedNickName(newNickName === oldNickName); // ๊ธฐ์กด ๋๋ค์๊ณผ ์๋ก์ด ๋๋ค์์ด ๊ฐ์ง ์์๋,์
๋ ฅ์ ์์ํ ๋ ํ์ฑํ
}}
value={member.nickName}
/>
<InputRightElement w={"100px"} mr={1}>
<Button
isDisabled={isDisableNickNameCheckButton}
onClick={handleCheckNickName}
colorScheme={"green"}
>
์ค๋ณต ํ์ธ
</Button>
</InputRightElement>
</InputGroup>
{isDisableNickNameCheckButton || (
<FormHelperText color={"red"}>
๋๋ค์ ์ค๋ณต ํ์ธ ํด์ผ ํฉ๋๋ค.
</FormHelperText>
)}
</FormControl>
</Box>
newNickName)์ ์ ์ํ๊ณ GET ์์ฒญ์ ํด์ ๋ฐ์์จ DB์ ์๋ ๋๋ค์(oldNickName)์ ์ ์ํฉ๋๋ค.const [isCheckedNickName, setIsCheckedNickName] = useState(true);
let isDisableNickNameCheckButton = false; // ํ์ฑํ
// ์๋ก์ด ๋๋ค์๊ณผ ๊ธฐ์กด ๋๋ค์์ด ๊ฐ๋ค๋ฉด ์ค๋ณต ํ์ธ ๋ฒํผ ๋นํ์ฑํ
if (member.nickName === oldNickName) {
isDisableNickNameCheckButton = true;
}
// ์๋ก์ด ๋๋ค์์ ์์ฑํ์ง ์์ผ๋ฉด ์ค๋ณต ํ์ธ ๋ฒํผ ๋นํ์ฑํ
if (member.nickName.trim().length === 0) {
isDisableNickNameCheckButton = true;
}
// ๋๋ค์ ์ค๋ณตํ์ธ ํ์ผ๋ฉด ์ค๋ณต ํ์ธ ๋ฒํผ ๋นํ์ฑํ
if (isCheckedNickName) {
isDisableNickNameCheckButton = true;
}
const [passwordCheck, setPasswordCheck] = useState("");
<Box>
<FormControl>
<FormLabel>๋น๋ฐ๋ฒํธ</FormLabel>
<Input
defaultValue={member.password}
placeholder={"์ํธ๋ฅผ ๋ณ๊ฒฝํ๋ ค๋ฉด ์
๋ ฅํ์ธ์."}
onChange={(e) => setMember({ ...member, password: e.target.value })}
/>
<FormHelperText color={"red"}>
์
๋ ฅํ์ง ์์ผ๋ฉด ๊ธฐ์กด ์ํธ๋ฅผ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค.
</FormHelperText>
</FormControl>
</Box>
<Box>
<FormControl>
<FormLabel>๋น๋ฐ๋ฒํธ ํ์ธ</FormLabel>
<Input onChange={(e) => setPasswordCheck(e.target.value)} />
{member.password === passwordCheck || (
<FormHelperText color={"red"}>
๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.
</FormHelperText>
)}
</FormControl>
</Box>
let isDisableSaveButton = false; //ํ์ฑํ
// ๋น๋ฐ๋ฒํธ๊ฐ ๊ฐ์ง ์์ผ๋ฉด ์ ์ฅ ๋ฒํผ ๋นํ์ฑํ
if (member.password !== passwordCheck) {
isDisableSaveButton = true;
}
// ์์ฑํ ๋๋ค์์ด ์๋ค๋ฉด ์ ์ฅ ๋ฒํผ ๋นํ์ฑํ
if (member.nickName.trim().length === 0) {
isDisableSaveButton = true;
}
// ๋๋ค์ ์ค๋ณต์ ํ์ธํ์ง ์์๋ค๋ฉด ๋นํ์ฑํ
if (!isCheckedNickName) {
isDisableSaveButton = true;
}
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>
<FontAwesomeIcon icon={faTriangleExclamation} />
๊ธฐ์กด ํจ์ค์๋ ํ์ธ
</ModalHeader>
<ModalBody>
<FormControl>
<FormLabel>๊ธฐ์กด ํจ์ค์๋</FormLabel>
<Input onChange={(e) => setOldPassword(e.target.value)} />
</FormControl>
</ModalBody>
<ModalFooter>
<Button onClick={handleClickSave} colorScheme={"blue"}>
ํ์ธ
</Button>
<Button onClick={onClose}>์ทจ์</Button>
</ModalFooter>
</ModalContent>
</Modal>
์ ์ฅ ๋ฒํผ์ ํด๋ฆญํ๋ฉด Modal์ด ๋ํ๋๊ณ Modal์์ ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํด์ผ ์์ ํ ์ ์๊ฒ ํฉ๋๋ค.member ๊ฐ์ฒด์ ๋ชจ๋ ์์ฑ์ ๋ณต์ฌํ๊ณ ์ฌ๊ธฐ์ oldPassword ์์ฑ์ ๋ง๋ถ์ธ ํํ๋ก ๋ณด๋
๋๋ค. ๊ทธ๋ฐ ๋ค์ ๊ธฐ์กด ํจ์ค์๋๋ฅผ ์
๋ ฅํด์ ๊ฐ๋ค๋ฉด ์์ ์ด ๋๊ณ ๊ฐ์ง ์์ผ๋ฉด ์์ ์ด ์๋ฉ๋๋ค.