React中使用Axios发送put请求仅更新特定字段的实现问题
解决方案
前端调整
- 首先修复初始化逻辑:原有useEffect会在页面加载时自动触发更新请求,改为加载时拉取当前公司的原有数据填充表单,避免用户需要重复填写未修改的字段
- 请求体过滤空字段:构造请求参数时仅保留用户有输入的非空字段,空值字段不提交,避免把不需要修改的字段以空值传给后端
修改后的前端代码示例:
function UpdateCompany(props): JSX.Element { const history = useHistory(); const [name , setName] = useState(''); const [email , setEmail] = useState(''); const [password , setPassword] = useState(''); // 页面加载时拉取原有公司数据填充表单 useEffect(() => { const fetchCompany = async () => { const res = await axios.get(globals.adminUrls.getCompany + props.location.state.id) const company = res.data setName(company.name) setEmail(company.email) setPassword(company.password) } fetchCompany() }, [props.location.state.id]); async function formData() { try { // 仅收集非空字段作为请求参数 const payload = {} if(name.trim()) payload.name = name if(email.trim()) payload.email = email if(password.trim()) payload.password = password const response = await axios.put<CompanyModel>(globals.adminUrls.updateCompany + props.location.state.id, payload); const updated = response.data; store.dispatch(companyUpdatedAction(updated)); notify.success(SccMsg.COMPANY_UPDATED) } catch (err) { notify.error(err); } } const handleSubmit = (e) => { e.preventDefault(); formData(); } return ( <div className="custom-field"> <h2>Update Company</h2> <div> <form onSubmit={handleSubmit} > <label>Name</label> <input type="text" name="name" value={name} onChange={(e)=>{setName(e.target.value)}}/> <label>Email</label> <input type="text" name="email" value={email} onChange={(e)=>{setEmail(e.target.value)}}/> <label>Password</label> <input type="text" name="password" value={password} onChange={(e)=>{setPassword(e.target.value)}}/> <input type="submit" name="submit"/> </form> </div> </div> ); } export default UpdateCompany;
后端调整
原有逻辑会直接将DTO全量转换为DAO覆盖数据库数据,需要改为增量更新逻辑:先查询数据库中已有的公司数据,仅将DTO中不为null的字段覆盖到已有对象上,其余字段保留原有值再保存。
修改后的Service代码示例:
public void updateCompany(@Valid int id, CompanyDto companyDto) throws DoesNotExistException, AlreadyExistsException { // 先查询现有公司数据 Company existingCompany = compRepo.findById(id) .orElseThrow(() -> new DoesNotExistException("Company does not exist")); // 仅更新非空字段 if (companyDto.getName() != null) { existingCompany.setName(companyDto.getName()); } if (companyDto.getEmail() != null) { existingCompany.setEmail(companyDto.getEmail()); } if (companyDto.getPassword() != null) { existingCompany.setPassword(companyDto.getPassword()); } // 校验字段重复等逻辑可以放在这里执行 compRepo.saveAndFlush(existingCompany); }
如果项目使用MapStruct做对象映射,可在Mapper接口上添加配置nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE,实现自动忽略null值的字段映射,无需手动编写if判断逻辑。
如果业务场景需要支持将字段清空为null,可取消前端的空值过滤,仅保留后端的增量更新逻辑,前端主动传null的字段后端会更新为null,未传的字段保留原有值。语义上增量更新更推荐使用PATCH请求,你也可以将请求方法从PUT改为PATCH更符合REST规范。
内容的提问来源于stack exchange,提问作者Shai Ace
相关产品推荐
相关产品推荐

