案例开发 - 日程管理 - 第四期
在第四期内容中,我们主要解决的是用 ajax 技术,实现用户在注册页面时候,输出要注册的用户名,当输入完用户名,点击空白处的时候,前端发送请求,检测用户名是否重复。
处理
在 regist.html 处,要进行如下处理:
在 controller 包下的 SysUserController 下应该新增加一个 checkUsernameUsed 方法:
增加这两段代码后,就可以实现我们预期的功能,但海撒存在一些问题:
1. 响应乱码问题,浏览器打开开发者模式,响应的“可用”中,显示的是乱码
2 响应格式不规范,处理方式不规范
后端响应回来的信息,应该有一个统一的格式,前后端共同遵守
==》
响应一个 JSON 串
{
"code":"100/200/300/400...":业务状态码 本次请求业务是否成功...
"message":业务状态码的补充说明
“data”:{ } 本次响应的数据 List<Schedule>...
... ...
}
3. 当校验不通过,即用户名已经被占用的时候,无法阻止表单提交
解决
创建 common 包
创建类 Result:
/*** 全局统一响应结果封装类* 用于标准化API接口的返回格式,包含状态码、响应消息和业务数据* @param <T> 响应数据的泛型类型,支持任意数据类型*/public class Result<T> {// 返回码:表示请求处理的状态(成功/失败/异常等)private Integer code;// 返回消息:对处理结果的文字描述(如"操作成功"、"参数错误"等)private String message;// 返回数据:业务处理的具体数据,泛型支持各种数据类型private T data;/*** 无参构造方法* 用于JSON序列化等场景*/public Result() {}/*** 构建基础响应对象* @param data 响应数据* @param <T> 数据类型* @return 包含数据的Result对象*/protected static <T> Result<T> build(T data) {Result<T> result = new Result<>();if (data != null) {result.setData(data);}return result;}/*** 构建完整响应对象* @param body 响应数据* @param code 状态码* @param message 响应消息* @param <T> 数据类型* @return 包含数据、状态码和消息的Result对象*/public static <T> Result<T> build(T body, Integer code, String message) {Result<T> result = build(body);result.setCode(code);result.setMessage(message);return result;}/*** 通过枚举构建响应对象* @param body 响应数据* @param resultCodeEnum 结果状态枚举(包含状态码和消息)* @param <T> 数据类型* @return 基于枚举的完整Result对象*/public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {Result<T> result = build(body);result.setCode(resultCodeEnum.getCode());result.setMessage(resultCodeEnum.getMessage());return result;}/*** 快速构建成功响应* @param data 响应数据* @param <T> 数据类型* @return 包含成功状态和数据的Result对象*/public static <T> Result<T> ok(T data) {return build(data, ResultCodeEnum.SUCCESS);}/*** 链式设置响应消息* @param msg 响应消息* @return 当前Result对象(支持链式调用)*/public Result<T> message(String msg) {this.setMessage(msg);return this;}/*** 链式设置状态码* @param code 状态码* @return 当前Result对象(支持链式调用)*/public Result<T> code(Integer code) {this.setCode(code);return this;}// Getter和Setter方法public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public T getData() {return data;}public void setData(T data) {this.data = data;}
}
创建类 ResultCodeEnum:
public enum ResultCodeEnum {SUCCESS(200, "success"),USERNAME_ERROR(501, "usernameError"),PASSWORD_ERROR(503, "passwordError"),NOTLOGIN(504, "notLogin"),USERNAME_USED(505, "usernameUsed");private Integer code;private String message;private ResultCodeEnum(Integer code, String message) {this.code = code;this.message = message;}public Integer getCode(){return code;}public String getMessage() {return message;}
}
我们要将这个 Result 对象转换成 JSON 串,需要导 jackson 包
controller 包下面的 SysUserControoller checkUsernameUsed 方法:
/*** 注册时,接收要注册的用户名,校验用户名是否被占用的业务接口** @param req* @param resp* @throws ServletException* @throws IOException*/protected void checkUsernameUsed(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 接收用户名String username = req.getParameter("username");// 调用服务处层业务处理方法查询用户名是否已经有对应的用户SysUser sysUser = userService.finByUsername(username);Result result = Result.ok(null);if (null != sysUser) {result = Result.build(null, ResultCodeEnum.USERNAME_USED);}// 将 result 对象转换为 JSON 串相应给客户端ObjectMapper objectMapper = new ObjectMapper();String info = objectMapper.writeValueAsString(result);// 告诉客户端响应的是一个是字符串resp.setContentType("application/json;charse=UTF-8");resp.getWriter().write(info);}
regist.html 修改:
这样就解决了两个问题。
在 SysUserController 下面的 checkUsernameUsed 中将 result 对象转换为 JSON 串的逻辑会经常被使用,我们可用抽象出一个方法:
public class WebUtil {private static ObjectMapper objectMapper;static {objectMapper = new ObjectMapper();}// 专门用于向客户端响应 JSON 串的方法public static void writeJson(HttpServletResponse resp, Result result) {// 告诉客户端响应的是一个是字符串resp.setContentType("application/json;charse=UTF-8");// 将 result 对象转换为 JSON 串相应给客户端try {String info = objectMapper.writeValueAsString(result);resp.getWriter().write(info);} catch (IOException e) {e.printStackTrace();}}
}