接着上一章所讲,本节主要实现一个简单的登录认证系统,涉及到的技术点包括API协议包装,全局异常统一处理等,这是真正的企业级核心技术,也是基础之一
1.创建rvo包
rvo即response value object,是API接口返回数据的包装
2.创建LoginRVO类
@Data public class LoginRVO { private long user_id; private String nickname; }
3.创建core包,新建ActionCode枚举类
public enum ActionCode { ERROR(0,"请求失败"), SUCCESS(1,"请求成功"), EXCEPTION(10,"服务器异常"), VALID(100,"参数校验异常"); public int code; public String message; ActionCode(int code, String message) { this.code = code; this.message = message; } }
在这个枚举类中定义常见的通用异常code
4.新建RVO协议类
@Data public class RVO<T> { private int code; private String message; private T data; public RVO(String message){ this(ActionCode.ERROR,message,null); } public RVO(ActionCode action){ this(action,null); } public RVO(ActionCode action,T data){ this(action.code,action.message,data); } public RVO(ActionCode action,String message,T data){ this(action.code,message,data); } public RVO(int code, String message) { this(code,message,null); } public RVO(int code, String message, T data) { this.code = code; this.message = message; this.data = data; } }
协议体如下:
code | mssage | data |
接口状态码 | 接口处理消息 | 返回数据,泛型结构 |
最终希望看到在请求一个接口后,返回如下信息
{"code":1,"message":"请求成功","data":{"user_id":1,"nickname":"admin"}}
5.修改GlobalExceptionHandler类
@RestControllerAdvice public class GlobalExceptionHandler { @ResponseBody @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.OK) public RVO exceptionHandler(Exception ex) throws IOException { if (ex instanceof MethodArgumentNotValidException) { BindingResult result = ((MethodArgumentNotValidException) ex).getBindingResult(); if (result.hasErrors()) { StringBuffer sb = new StringBuffer(); printBindException(sb, result); return new RVO<>(ActionCode.VALID,sb.toString(),null); } } return new RVO<>(ActionCode.EXCEPTION); } private void printBindException(StringBuffer message, BindingResult result) { List<ObjectError> allErrors = result.getAllErrors(); for (int i = 0; i < allErrors.size(); i++) { message.append(allErrors.get(i).getDefaultMessage()); if (allErrors.size() > 1 && i < allErrors.size() - 1) { message.append(","); } } } }
当发生异常时,我们希望接口返回
{"code":100,"message":"密码不能为空","data":null}
6.创建UserController类
@Controller @RequestMapping("/user") public class UserController { @ResponseBody @RequestMapping(value = "/login",method = RequestMethod.POST) public RVO login(@RequestBody @Valid LoginRTO login) { if(!login.getNickname().equals("admin") || !login.getPassword().equals("123")){ return new RVO<>("用户名密码错误"); } LoginRVO rvo = new LoginRVO(); rvo.setUser_id(1); rvo.setNickname(login.getNickname()); return new RVO<>(ActionCode.SUCCESS,rvo); } }
7.新建login.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <h2>用户登录</h2><hr> <input id="nickname" type="text" value="admin"/></br> <input id="password" type="text" value="123"/></br> <button onclick='login()'>登录</button></br> <div id="tip"></div> <script src="jquery.min.js"></script> <script> function login(){ var nickname = $("#nickname").val(); var password = $("#password").val(); $.ajax({ url: 'http://localhost:8080/user/login', type: "post", contentType: 'application/json;charset=utf-8', dataType: 'json', data: JSON.stringify({ nickname: nickname, password: password }), success: function (res) { if(res.code == 1){ $("#tip").html("用户ID = "+res.data.user_id+" 用户名 = "+res.data.nickname); }else{ $("#tip").html(res.message); } }, error: function () { $("#tip").html("连接失败"); } }); } </script> </body> </html>
此时目录结构如下
8.运行
打开浏览器,输入
http://localhost:8080/login.html
抓包分析,查看一下结构
删除密码,再次点击登录测试
抓包分析,查看一下结构