# DevOps更新说明
# Controller接口改造说明
# 一、注解改造
原代码:
@Path("/api/uc/apply-users")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Api(description = "申请用户管理对外接口")
改造后:
import org.springframework.http.MediaType;
@RequestMapping(value = "/api/uc/apply-users", consumes = {MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_JSON_VALUE})
@Api(tags="IUserController【对应类名】",description = "申请用户管理对外接口")
# 二、方法改造
Get类型源码:
@GET
@ApiOperation("查询申请用户")
PageResultList<ApplyUser> queryApplyUsers(@QueryParam("empName") @ApiParam("申请用户名称") String empName,
@QueryParam("companyName") @ApiParam("公司名称") String companyName,
@QueryParam("pageIndex") @ApiParam("分页索引") int pageIndex,
@QueryParam("pageSize") @ApiParam("分页大小") int pageSize) throws Exception;
改造后:
@GetMapping
@ApiOperation("查询申请用户")
PageResultList<ApplyUser> queryApplyUsers(@RequestParam(name = "empName", required = false) @ApiParam("申请用户名称") String empName,
@RequestParam(name = "companyName", required = false) @ApiParam("公司名称") String companyName,
@RequestParam(name = "pageIndex", required = false, defaultValue = "0") @ApiParam("分页索引") int pageIndex,
@RequestParam(name = "pageSize", required = false, defaultValue = "0") @ApiParam("分页大小") int pageSize) throws Exception;
说明: 1、有path映射时 如 @Path("/{applyId}") 把path加到value参数里 @GetMapping(value = "/{applyId}") 2、参数为基本数据类型时,推荐加上 defaultValue = "基本数据类型初值" 因为现在使用Spring Restful框架参数默认必填的(可以加上非必填,但是值没有初始化),以前Resteasy是非必填的,所以有可能使用的时候没传参数,默认用的初值,所以现在推荐手动赋上初值。 3、详细改造映射【RESTful API 开发手册 - 请求与响应规范.md】
Post类型源码:
@Path("/actions/create")
@POST
@ApiOperation("新增申请用户")
ApplyUser createApplyUser(@ApiParam("用户申请信息") ApplyUser applyUser) throws Exception;
改造后:
@PostMapping(value = "/actions/create")
@ApiOperation("新增申请用户")
ApplyUser createApplyUser(@RequestBody @ApiParam("用户申请信息") ApplyUser applyUser) throws Exception;
Put类型源码:
@Path("/{applyId}")
@PUT
@ApiOperation("更新用户申请信息")
@Permission("admin_apply_user_edit")
ApplyUser modifyApplyUser(@ApiParam("用户申请信息") ApplyUser applyUser) throws Exception;
改造后:
@PutMapping(value = "/{applyId}")
@ApiOperation("更新用户申请信息")
@Permission("admin_apply_user_edit")
ApplyUser modifyApplyUser(@RequestBody @ApiParam("用户申请信息") ApplyUser applyUser) throws Exception;
Delete类型源码:
@Path("/{applyId}")
@DELETE
@ApiOperation("删除申请用户")
@Permission("admin_apply_user_remove")
ApplyUser removeApplyUser(@PathParam("applyId") @ApiParam("申请ID") String applyId) throws Exception;
改造后:
@PutMapping(value = "/{applyId}")
@ApiOperation("更新用户申请信息")
@Permission("admin_apply_user_edit")
ApplyUser modifyApplyUser(@RequestBody @ApiParam("用户申请信息") ApplyUser applyUser) throws Exception;
# Controller实现类改造说明
# 一、注解改造
@Controller改成@RestController
@Controller
public class ApplyUserController implements IApplyUserController
@RestController
public class ApplyUserController implements IApplyUserController
# 多部分文件参数说明
MultipartFormDataInput改造需要具体情况具体分析
MultipartFormDataInput改成@RequestParam MultipartFile或者List
# MultipartFormDataInput更新说明
# Resteasy 中的使用
在Resteasy中,你可以使用 MultipartFormDataInput
来接收多部分请求,并通过 InputPart
来访问其中的具体部分。例如:
@POST
@Path("/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(MultipartFormDataInput input) {
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
List<InputPart> inputParts = uploadForm.get("file");
for (InputPart inputPart : inputParts) {
try {
// MultipartBodyDataPart bodyDataPart = (MultipartBodyDataPart) inputPart.getBody(MultipartBodyDataPart.class, null);
// InputStream inputStream = bodyDataPart.getInputStream();
InputStream inputStream = inputPart.getBody(InputStream.class, null);
// 处理文件流 获取文件名称
MultivaluedMap<String, String> headers = attachmentPart.getHeaders();
String[] contentDispositions = headers.getFirst("Content-Disposition").split(";");
String fileName = null;
for (String dispositon : contentDispositions) {
if (dispositon.contains("filename=")) {
fileName = CommonUtil.splitExcludeBlank(CommonUtil.urlDecode(dispositon), "[=\"]").toArray(new String[0])[1];
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
return Response.ok().build();
}
在这个例子中,我们通过 MultipartFormDataInput
获取了表单数据,并通过 InputPart
访问了名为 "file" 的上传文件部分。
# 改为 Restful(Spring)中的使用
MultipartFile的名称很重要,需要和上传的请求体里一致才能获取到。
在Spring的Restful接口中,你可以使用 MultipartFile
来接收上传的文件。例如:
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> uploadFile(@RequestParam("file") @ApiParam("文件") MultipartFile file) {
try {
// 获取输入流
InputStream attachmentInputStream = file.getInputStream();
String fileName = file.getOriginalFilename();
// 处理文件,例如保存到磁盘
file.transferTo(new File("path/to/destination/" + file.getOriginalFilename()));
return ResponseEntity.ok("File uploaded successfully");
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Could not upload the file");
}
}
多个文件用list接收,为了通用我们改造的时候直接用List
public ResponseEntity<String> uploadFile(@RequestParam @ApiParam("多文件") List<MultipartFile> files)
在这个例子中,我们使用 @RequestParam
注解来指定请求参数 "file" (不写也可以,但是对象名字得一致) 应该被映射到 MultipartFile
类型的参数上。然后我们可以使用 MultipartFile
提供的方法来处理上传的文件。
MultipartFile的名称很重要,需要和上传的请求体里一致才能获取到。
在Spring的Restful接口中,你可以使用 MultipartFile
来接收上传的文件。例如:
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> uploadFile(@RequestParam("file") @ApiParam("文件") MultipartFile file) {
try {
// 获取输入流
InputStream attachmentInputStream = file.getInputStream();
String fileName = file.getOriginalFilename();
// 处理文件,例如保存到磁盘
file.transferTo(new File("path/to/destination/" + file.getOriginalFilename()));
return ResponseEntity.ok("File uploaded successfully");
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Could not upload the file");
}
}
多个文件用list接收,为了通用我们改造的时候直接用List
public ResponseEntity<String> uploadFile(@RequestParam @ApiParam("多文件") List<MultipartFile> files)
在这个例子中,我们使用 @RequestParam
注解来指定请求参数 "file" (不写也可以,但是对象名字得一致) 应该被映射到 MultipartFile
类型的参数上。然后我们可以使用 MultipartFile
提供的方法来处理上传的文件。
# 关联的参数名称不确定时
通过 MultipartHttpServletRequest multipartHttpServletRequest multipartHttpServletRequest会自动将传入的表单拆成两部分分别放入文件和非文件参数里。
对于文件类型 multipartHttpServletRequest.getMultiFileMap();
可以遍历map来实现
Map<String, List<MultipartFile>> multiFileMap = multipartHttpServletRequest.getMultiFileMap();
for (Entry<String, List<MultipartFile>> entry:multiFileMap.entrySet()) {
workitemService.addWorkitemAttachments(workitemId, entry.getKey(), entry.getValue());
}
# 如果还包含非文件类型但参数名不确定,或者在某一范围时
multipartHttpServletRequest.getParameterMap()
Map<String, String[]> multiFileMap = multipartHttpServletRequest.getParameterMap();
String[] data = multipartHttpServletRequest.getParameterValues("data");#可以根据key获取String数组 一般默认[0]即可
如果请求表单里既有文件又有非文件类似json字符串时 如果已知非文件的key值建议如下实践 例:构建介质上传接口,请求内容
data: {"username":null,"password":null,"repo":null,"groupId":null,"artifactId":"testfile","version":"1.0.0","alias":"file1","classifier":null,"fileName":"file.txt","projectId":"21","artifactRepositoryId":"1","artifactCategory":"obj","fileSize":5891,"componentId":"21","systemId":"2","needInsertDB":true,"repoUrl":"http://10.15.15.133:8081/repository/DEMO072501-demoJar/"}
file: (binary)
通过字符串文本的key即可获取对应内容,而不是再请求体里在解析获取
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ApiOperation("介质上传")
@Permission("project_artifact_upload")
void uploadArtifact(@RequestParam @ApiParam("附件") List<MultipartFile> file,
@RequestParam("data") @ApiParam("介质信息") String dataJson) throws Exception;
# RESTful说明
# 一、请求方法规范
# POST 请求
使用
@PostMapping
注解定义 POST 请求的 URI。使用
@MultiRequestBody
注解接收请求体中的 JSON 数据。示例:
@PostMapping("/versions") public ResponseEntity<?> createVersion(@MultiRequestBody Version version) { // 处理逻辑... return ResponseEntity.ok().build(); }
# PUT 请求
使用
@PutMapping
注解定义 PUT 请求的 URI。与 POST 请求类似,使用
@MultiRequestBody
注解接收请求体中的 JSON 数据。示例:
@PutMapping("/versions/{versionId}") public ResponseEntity<?> modifyVersion(@PathVariable Long versionId, @RequestBody Version version) { // 处理逻辑... return ResponseEntity.ok().build(); }
# DELETE 请求
使用
@DeleteMapping
注解定义 DELETE 请求的 URI。对于简单的 DELETE 请求,通常不需要
@MultiRequestBody
注解,而是使用 URI 参数或请求参数来标识要删除的资源。示例:
@DeleteMapping("/versions/{versionId}") public ResponseEntity<?> removeVersion(@PathVariable Long versionId) { // 处理逻辑... return ResponseEntity.ok().build(); }
# GET 请求
使用
@GetMapping
注解定义 GET 请求的 URI。使用
@RequestParam
注解接收查询参数。required = false 非必填
defaultValue = "" 预设默认值
示例:
@GetMapping("/versions") public ResponseEntity<List<Version>> queryVersionsByCriteria( @RequestParam(name = "versionName", required = false, defaultValue = "") String versionName, // 其他参数... ) { // 处理逻辑... return ResponseEntity.ok(versions); }
# 二、请求与响应体规范
- 请求体
- 请求体应使用 JSON 格式。
- 使用
@RequestBody
注解接收请求体中的 JSON 数据,并将其反序列化为 Java 实体类对象。
- 响应体
- 响应体应使用 JSON 格式。
- 对于成功的请求,通常返回 HTTP 状态码 200,并在响应体中返回相应的数据。
- 对于失败的请求,应返回适当的 HTTP 状态码(如 400、404、500 等),并在响应体中返回错误信息。
# 三、注解使用规范
使用
@RestController
注解标识控制器类。使用
@RequestMapping
(或其变体如@GetMapping
、@PostMapping
等)注解定义 URI 和 HTTP 方法。使用
@PathVariable
注解从 URI 中提取路径变量。使用
@RequestParam
注解从查询参数中提取参数值。使用
@RequestBody
注解接收请求体中的 JSON 数据。使用
@ResponseBody
(但通常在@RestController
下的方法上不需要显式使用,因为@RestController
默认包含了@ResponseBody
)注解表示该方法的返回值将作为响应体返回给客户端。参考如下 MediaType.APPLICATION_JSON_UTF8_VALUE过时了可以用 MediaType.APPLICATION_JSON_VALUE代替
@Api(tags = "Version管理") @RestController @RequestMapping(value = "/api/rest/service/versions", consumes = { MediaType.APPLICATION_JSON_UTF8_VALUE }, produces = { MediaType.APPLICATION_JSON_UTF8_VALUE })
# 四、其他规范
确保 API 的 URI 设计清晰、简洁,并遵循 RESTful 风格。
使用 HTTP 状态码来表示请求的成功或失败。
在 API 文档中清晰描述每个 API 的 URI、请求方法、请求参数、响应数据和错误码等信息。
如 @ApiParam("")
@ApiOperation("条件查询字典类型,分页展示") @GetMapping public PageResultList<DictType> queryDictTypesByCriteria( @ApiParam("字典类型编码") @RequestParam(name = "code", required = false) String code, @ApiParam("字典类型名称") @RequestParam(name = "name", required = false) String name, @ApiParam("父字典类型ID") @RequestParam(name = "parentId", required = false) String parentId, @ApiParam("字典类型层级") @RequestParam(name = "levels", required = false) String levels, @ApiParam("每页条数") @RequestParam(name = "pageSize", required = false, defaultValue = "0") int pageSize, @ApiParam("当前页数") @RequestParam(name = "pageIndex", required = false, defaultValue = "0") int pageIndex, @ApiParam("排序字段:多字段,分割") @RequestParam(name = "orderFields", required = false) String orderFields, @ApiParam("排序规则:ASC OR DESC") @RequestParam(name = "orderDirection", required = false) String orderDirection) throws Exception { return dictTypeService.queryDictTypesByCriteria(code, name, parentId, levels, pageSize, pageIndex, orderFields, orderDirection); }
遵循良好的编码习惯和代码规范,确保代码的可读性和可维护性。
resteasy与springmvc注解映射
resteasy | spring mvc | 说明 |
---|---|---|
@Path | @RequestMapping(GetMapping,PostMapping, PutMapping, DeleteMapping)的value值 | path |
@GET,POST, PUT, DELETE | @GetMapping,PostMapping, PutMapping, DeleteMapping | method |
@PathParam,不是必填 | @PathVariable,默认是必填 | path param |
@HeaderParam,不是必填 | @RequestHeader,默认是必填 | head param |
@QueryParam,不是必填 | @RequestParam,默认是必填 | query param |
@FormParam,不是必填 | @RequestParam,默认是必填 | form param |
没有注解 | @RequestBody,默认是必填 @SdoRequestBody(6.7更新eos底层时新增的自定义注解 用于兼容Sdo实体,自动映射Interface对应的实现类) | body param |
@JSONParam | @MultiRequestBody | 多body param |
@Context,类HttpServletRequest或者HttpServletResponse | 没有,直接使用类HttpServletRequest或者HttpServletResponse | 获取HttpServletRequest或者HttpServletResponse(下载用) |
MultipartFormDataInput类型的参数@Consumes(MediaType.MULTIPART_FORM_DATA) | @RequestParam MultipartFile或者List | 上传 |