目录
前言
在vue项目中,我们修改表的某一行的部分字段时,是需要用axios中patch类型的请求来完成的,所以掌握发送、接收patch请求,是绕不开的一环。
一.问题描述
二.后端实现
1.分析
分析一下:由于是修改发票表的某一行的某个字段(即部分资源),所以要用Patch请求来完成该操作。 请求的参数应该有:id(代表我们要修改的那行发票记录)、日结状态(是个整数,如:3代表审核通过)。
注意:
①一般使用patch请求时,id参数直接就放在请求路径中了。因为这样简洁明了。
②其他参数应该放到一个data对象中。
2.检查后端拦截器,看看是否允许接收Patch类型的请求
注意:这一步很重要,如果你没配置后端拦截器,那么这一步可以跳过。如果你配置了后端拦截器,就好检查一下你的拦截器是否允许PATCH请求通过。
博主就是因为没有好好检查,整了半天才发现是这个问题导致前端代码报错。
3.编写Dto
注意:
①patch请求要用data对象来传递参数。(除了get请求用params传递参数以外,其他类型的请求很少用params传递参数)。
②在InvoiceDto中,我们为什么没写id呢?因为我们想在patch请求的请求路径中携带id参数,所以就不在该Dto中携带了。
4.编写controller层
@RestController//表明这是一个controller层,并且自动将对象转为JSON格式返回
@RequestMapping("/api/invoice")//该controller的访问路径
public class InvoiceController {
@Autowired
private InvoiceService invoiceService;
//根据id,修改某个发票的状态(dailyState)
@PatchMapping("/{id}/dailyState")
public Result updateInvoiceDailyState(@PathVariable Integer id,@RequestBody InvoiceDto invoiceDto){
//System.out.println(id + "--" + invoiceDto.toString());
int i = invoiceService.updateInvoiceDailyState(id, invoiceDto);
if(i>0){
return new Result(200, "审核成功");
}else{
return new Result(500, "审核失败");
}
}
}
注意:
①我们在patch请求路径中携带id参数的形式如:@PatchMapping("/{id}/dailyState"),要用大括号{ }给id参数括起来。
②"/{id}/dailyState"的意思是:我们要修改该id对应的那张发票的日结状态dailyState,这样就能表示该patch请求是用来根据id修改某张发票的日结状态了。这做到了见名知意。
③要用@PathVariable注解来接收请求路径中的参数。
④要用@RequestBody注解来接收请求中的data对象参数。
5.编写service层
service层:
public interface InvoiceService {
//根据id,修改某条发票记录的日结状态(dailyState)
public int updateInvoiceDailyState(Integer id, InvoiceDto invoiceDto);
}
serviceImpl层:
@Service
public class InvoiceServiceImpl implements InvoiceService {
@Autowired
private InvoiceMapper invoiceMapper;
//根据id,修改某条发票记录的日结状态(dailyState)
public int updateInvoiceDailyState(Integer id, InvoiceDto invoiceDto) {
int i = invoiceMapper.updateInvoiceDailyState(id, invoiceDto);
return i;//返回的是影响行数
}
}
6.mapper层
@Mapper
public interface InvoiceMapper {
//根据id,修改某条发票记录的日结状态(dailyState)
@Update("update invoice set daily_state = #{invoiceDto.dailyState} where id=#{id}")
public int updateInvoiceDailyState(Integer id, InvoiceDto invoiceDto);
}
注意:当mapper层中,形参列表中不单单只有对象类型的参数时,我们访问对象中的属性,要通过#{对象名.属性名}的形式。 反之,要是形参列表中,只有对象参数,那么直接#{属性名}即可。
7.使用apifox,测试后端接口的可用性
三.前端实现
1.封装api(本质是axios请求)
import request from '@/request/request'
//编写方法“根据id,修改某张发票的日结状态(dailyState)”,并将其暴露出去
export function updateInvoiceDailyState(id, data){
return request.patch(`/api/invoice/${id}/dailyState`,data);
}
注意:
①我们在前端发送axios请求时,如果要携带路径参数,那么就不能用单引号来盛请求路径,而是用反引号(也称“飘号”,如下图)
②上面的代码中,id表示要修改的发票id,data表示要修改的字段(放在了data对象中)。
2.在vue代码中,使用该api发送patch请求给后端
//点击气泡确认框的“通过”按钮,触发事件passInvoice(row)
const passInvoice = async (row) => {
//alert("通过");
//alert(JSON.stringify(row))//这是点击的那一行的发票的全部信息
//根据发票id,将该发票的状态改为审核通过(daily_state == 3)
//构造参数对象data
const invoiceDto = {
dailyState: 3
}
const res = await updateInvoiceDailyState(row.id, invoiceDto);
if(res.code == 200){
//弹框提示审核成功
ElMessage.success(res.message);
//刷新表格(查询所有待审核的发票)
doQueryAllInvoice({dailyState:"2"});
}else{
ElMessage.error("审核失败");
}
}
3.展示效果
四.重要的点
1、除了get请求使用params传递参数以外,其他类型的请求很少使用params传递参数,而是使用data对象来传递参数(后端使用@RequestBody注解来接收)。
2、patch请求代表修改某个id对应的一行数据的部分字段。此时尽量将id参数放在请求路径中(后端使用@PathVariable注解来接收请求路径参数) ,因为这样简洁明了、一眼能看出来,而且更加符合RESTful请求风格的要求。
3、其实将id放在data对象中传递也可以,只是不推荐而已,因为这样不简洁。
4、patch请求用来修改部分资源(即:一行中的部分字段)。
put请求用来修改全部资源(即:一行中的所有字段)。
五.注意事项
1.出现的问题
//编写方法“毕诊某个患者(修改患者病历状态 + 修改患者挂号状态)”,并将其暴露出去 export function finishMedical(data1, data2){ return request.patch('/api/medical_record/finishMedical', { params:{ medicalId: data1, registerId: data2 } }); }
这是前端封装的axios请求,为什么不能被下面的后端接口接收?
//毕诊某个患者(修改患者病历状态 + 修改患者挂号状态) @PatchMapping("/finishMedical") public Result finishMedical(@RequestParam(value = "medicalId") Integer medicalId, @RequestParam(value = "registerId") Integer registerId){ System.out.println(medicalId + " " + registerId ); medicalRecordService.finishMedical(medicalId, registerId); return new Result(200, "毕诊成功"); }
2.问题的根本原因
问题出在 请求参数的传递方式 上。你的前后端不匹配是因为:
前端代码 使用
axios.patch
时,将参数放在了data
对象里(第二个参数),但同时又用params
包裹,这会导致:
- 参数实际上被放在 请求体(body) 里发送
- 而不是作为 URL 查询参数(query params)
后端代码 使用
@RequestParam
注解,表示它期望参数是通过 URL 查询参数 传递的(即?medicalId=123®isterId=456
),而不是请求体。解决方案
方案 1:前端修改(推荐)
如果后端要求用
@RequestParam
,前端应该这样传:javascript
换行复制代码
1export function finishMedical(medicalId, registerId) { 2 return request.patch('/api/medical_record/finishMedical', null, { 3 params: { // axios 的 params 会拼接到 URL 4 medicalId, 5 registerId 6 } 7 }); 8}
- 这里
params
是 axios 的配置项,会自动转换成?medicalId=xxx®isterId=xxx
方案 2:后端修改(如果允许)
如果后端可以改,可以用
@RequestBody
接收:java
换行复制代码
1@PatchMapping("/finishMedical") 2public Result finishMedical(@RequestBody Map<String, Integer> params) { 3 Integer medicalId = params.get("medicalId"); 4 Integer registerId = params.get("registerId"); 5 // ... 6}
- 这样前端原来的代码就能工作
总结
@RequestParam
→ 需要前端用params
发送(URL 查询参数)@RequestBody
→ 需要前端用data
发送(请求体)- 你的问题是因为前端用
data
发送,但后端用@RequestParam
接收,导致参数无法正确解析。
3.总结
patch请求一般使用data对象来传递参数。
但是我们也可以使用请求参数来传递参数,只不过patch请求的参数列表的第二个位置用null填充,表示data对象为空(即:不使用data对象来传递参数)。
结语
以上就是我们在vue项目中,发送一个patch请求的例子,我们要好好了解这一块。
喜欢本篇文章的话,可以留个免费的关注~~