记录一点开发技巧
记录一个开发常见的风格
1.RESTful
好的,我们来详细讲解一下 RESTful(通常写作 RESTful 或 REST)架构风格。这是现代 Web 服务和 API 设计的核心范式。
什么是 RESTful?
REST(REpresentational State Transfer)是一种软件架构风格,由 Roy Fielding 在 2000 年提出。它定义了一套约束条件,用于创建可扩展、松耦合的网络服务(Web APIs)。
RESTful 是指符合 REST 原则的 API 或服务。
RESTful API 关键设计
1. 资源(Resources)
- 所有数据抽象为资源(用户、订单、产品等)
- 用 URI(统一资源标识符) 定位资源
示例:/books
→ 所有书籍/books/42
→ ID=42 的书籍
2. HTTP 方法(动词)
方法 | 作用 | 幂等性 | 示例 |
---|---|---|---|
GET | 获取资源 | 是 | GET /users |
POST | 创建新资源 | 否 | POST /users |
PUT | 更新/替换整个资源 | 是 | PUT /users/1 |
PATCH | 部分更新资源 | 否 | PATCH /users/1 |
DELETE | 删除资源 | 是 | DELETE /users/1 |
幂等性:多次执行效果相同(如重复
PUT
不改变结果)
3. 状态码(Status Codes)
用 HTTP 状态码表示结果:
200 OK
:成功201 Created
:资源创建成功400 Bad Request
:客户端错误401 Unauthorized
:未认证404 Not Found
:资源不存在500 Internal Server Error
:服务器错误
一个完整的 RESTful 示例
用户管理 API
功能 | HTTP 方法 | URI | 说明 |
---|---|---|---|
获取所有用户 | GET | /users | 返回用户列表 |
创建用户 | POST | /users | 提交新用户数据 |
获取单个用户 | GET | /users/{id} | 返回 ID 对应的用户 |
更新用户 | PUT | /users/{id} | 替换整个用户数据 |
部分更新 | PATCH | /users/{id} | 只更新指定字段(如邮箱) |
删除用户 | DELETE | /users/{id} | 删除该用户 |
常见误区
- ❌ 用动词命名 URI(如
/getUser
→ 应改用GET /users
) - ❌ 忽略 HTTP 状态码(所有响应都返回
200
) - ❌ 在 GET 请求中使用 Body 传递参数
- ❌ 返回 HTML 页面而非结构化数据(JSON/XML)
示例代码:
@Data
public class Result<T> implements Serializable {private Integer code; //编码:1成功,0和其它数字为失败private String msg; //错误信息private T data; //数据public static <T> Result<T> success() {Result<T> result = new Result<T>();result.code = 1;return result;}public static <T> Result<T> success(T object) {Result<T> result = new Result<T>();result.data = object;result.code = 1;return result;}public static <T> Result<T> success(String msg,T object) {Result<T> result = new Result<T>();result.data = object;result.msg = msg;result.code = 1;return result;}public static <T> Result<T> error(String msg) {Result result = new Result();result.msg = msg;result.code = 0;return result;}}@PostMapping("/upload")public Result<String> uploadFile(@RequestParam("file") MultipartFile file) {boolean saved = markdownDocsService.saveFile(file);if (saved)return Result.success("上传成功");return Result.error("上传失败");}
2.全局异常处理
1.我们定义一个异常的枚举类用来返回异常信息
@Getter
@AllArgsConstructor
@ToString
public enum ResponseEnum {SUCCESS(1, "成功"),ERROR(-1, "服务器内部错误"),//-1xx 服务器错误BAD_SQL_GRAMMAR_ERROR(-101, "sql语法错误"),SERVLET_ERROR(-102, "servlet请求异常"), //-2xx 参数校验DELETE_FILE_FAILED(103, "删除文件错误"),UPLOAD_ERROR(-103, "文件上传错误"),EXPORT_DATA_ERROR(104, "数据导出失败"),DATA_NOt_EXISITS(105, "数据不存在"),PARAM_IS_NULL_ERROR(-105, "参数不能为空"),IMPORT_DATA_ERROR(106, "数据导入失败"),FILE_IS_EMPTY(107, "上传文件内容为空"),DISALLOW_DELETE_DATA(108, "该数据有关联数据不能删除"),TOO_MANY_REQUESTS(109, "请求太频繁了"),//-2xx 参数校验USRE_ID_NULL_ERROR(-201, "用户Id不能为空"),MOBILE_NULL_ERROR(-202, "手机号码不能为空"),MOBILE_ERROR(-203, "手机号码不正确"),PASSWORD_NULL_ERROR(204, "密码不能为空"),CODE_NULL_ERROR(205, "验证码不能为空"),CODE_ERROR(206, "验证码错误"),MOBILE_EXIST_ERROR(207, "手机号已被注册"),LOGIN_MOBILE_ERROR(208, "用户不存在"),LOGIN_PASSWORD_ERROR(209, "密码错误"),LOGIN_LOKED_ERROR(210, "用户被锁定"),LOGIN_AUTH_ERROR(-211, "未登录"),REGISTER_FAIL(212, "注册失败"),USER_REPEAT(-212, "重复注册"),USER_PWD_ERROR(213, "用户密码错误"),ACCOUNT_UNREGISTER(-213, "用户未注册"),ACCOUNT_UNLOGIN(214, "用户未登录"),USER_NOT_EXIST(215, "用户不存在"),USER_ISNOT_ROLE(215, "用户角色不匹配"),USERNAME_IS_EXIST(216, "用户名已存在"),ORG_NOT_EXIST(217, "机构信息不存在"),DELETE_SUCCESS(218, "删除成功"),DELETE_FAIL(219, "删除失败"),UPDATE_SUCCESS(220, "更新成功"),UPDATE_FAIL(221, "更新失败"),UPDATE_ERROR(222, "更新操作异常"),USER_BIND_IDCARD_EXIST_ERROR(-301, "身份证号码已绑定"),USER_NO_BIND_ERROR(302, "用户未绑定"),LEND_INVEST_ERROR(305, "当前状态无法投标"),LEND_FULL_SCALE_ERROR(306, "已满标,无法投标"),NOT_SUFFICIENT_FUNDS_ERROR(307, "余额不足,请充值"),PAY_UNIFIEDORDER_ERROR(401, "统一下单错误"),ALIYUN_SMS_LIMIT_CONTROL_ERROR(-502, "短信发送过于频繁"),//业务限流ALIYUN_SMS_ERROR(-503, "短信发送失败"),//其他失败WEIXIN_CALLBACK_PARAM_ERROR(-601, "回调参数不正确"),WEIXIN_FETCH_ACCESSTOKEN_ERROR(-602, "获取access_token失败"),WEIXIN_FETCH_USERINFO_ERROR(-603, "获取用户信息失败"),USER_TYPE_ERROR(-604, "用户信息异常"),;private final Integer code;//状态码private final String message;//消息ResponseEnum(int code, String message) {this.code = code;this.message = message;}
}
2.自定义一个异常类
/*** 业务异常*/
@Getter
public class BusinessException extends RuntimeException {//状态码private Integer code;public BusinessException(String message, Integer code) {super(message);this.code = code;}public BusinessException(ResponseEnum responseEnum) {super(responseEnum.getMessage());this.code = responseEnum.getCode();}public BusinessException(ResponseEnum responseEnum, Throwable cause) {super(responseEnum.getMessage(),cause);this.code = responseEnum.getCode();}
}
3.全局异常处理
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {/*** 未定义异常处理*/@ExceptionHandler(Exception.class)public Result<Object> exception(Exception e) {log.error(e.getMessage(), e);return Result.error("系统异常");}/*** 参数绑定异常处理*/@ExceptionHandler(BindException.class)public Result<Object> handleBindException(BindException e) {return Result.error(e.getMessage());}@ExceptionHandler(ExecutionException.class)public Result<Object> handleExecutionException(ExecutionException e) {log.error(e.getMessage(), e);Result<Object> result = new Result<>();result.setMsg(REGISTER_FAIL.getMessage());result.setCode(REGISTER_FAIL.getCode()); // 设置特定错误码return result;}/*** 自定义业务异常处理*/@ExceptionHandler(BusinessException.class)public Result<Object> handleBusinessException(BusinessException e) {log.error(e.getMessage(), e.getCause());Result<Object> result = Result.error(e.getMessage());result.setCode(e.getCode()); // 设置自定义错误码return result;}@ExceptionHandler(NotLoginException.class)public Result <Object> handleNotLoginException(NotLoginException e) {log.error(e.getMessage(), e);Result<Object> result = Result.error(ResponseEnum.ACCOUNT_UNLOGIN.getMessage());result.setCode(ResponseEnum.ACCOUNT_UNLOGIN.getCode()); // 设置特定错误码return result;}@ExceptionHandler(SQLException.class)public Result<Object> handleSQLException(SQLException e) {log.error(e.getMessage(), e);Result<Object> result = Result.error(ResponseEnum.IMPORT_DATA_ERROR.getMessage());result.setCode(ResponseEnum.IMPORT_DATA_ERROR.getCode()); // 设置特定错误码return result;}/*** Servlet请求相关异常处理*/@ExceptionHandler({NoHandlerFoundException.class,HttpRequestMethodNotSupportedException.class,HttpMediaTypeNotSupportedException.class,MissingPathVariableException.class,MissingServletRequestParameterException.class,HttpMessageNotReadableException.class,HttpMessageNotWritableException.class,MethodArgumentNotValidException.class,HttpMediaTypeNotAcceptableException.class,ServletRequestBindingException.class,ConversionNotSupportedException.class,MissingServletRequestPartException.class,AsyncRequestTimeoutException.class})public Result<Object> handleServletException(Exception e) {log.error(e.getMessage(), e);Result<Object> result = Result.error(ResponseEnum.SERVLET_ERROR.getMessage());result.setCode(ResponseEnum.SERVLET_ERROR.getCode()); // 设置特定错误码return result;}}
4.在处理业务是我们就可以利用抛出异常的方法处理错误情况
public MarkdownDocsServiceImpl() {try {// 使用 ClassPathResource 确保路径正确指向 resources/document 目录ClassPathResource resource = new ClassPathResource(MD_SAVE_PATH);this.rootLocation = resource.getFile().toPath();} catch (Exception e) {throw new RuntimeException("初始化文件存储路径失败: " + MD_SAVE_PATH, e);}}
3.讲到这里了,再给大家讲一个 ClassPathResour
这个我也是今天刚用,很神奇,我的业务需求是我想存储前端的md文件到我的项目中下次启动的时候可以进行处理,当然还要立刻处理一下,存储是为了持久化,数据库我也想过,暂时还没有实现,我先尝试了这一种
ClassPathResource resource = new ClassPathResource(MD_SAVE_PATH);
String MD_SAVE_PATH ="classpath:document"
他会把文件存储到target的classes里面,很神奇我还在研究它的原理,