diff --git a/src/main/java/com/jiudian/manage/until/FileUtil.java b/src/main/java/com/jiudian/manage/until/FileUtil.java index 62fe0b8..a94b240 100644 --- a/src/main/java/com/jiudian/manage/until/FileUtil.java +++ b/src/main/java/com/jiudian/manage/until/FileUtil.java @@ -1,18 +1,44 @@ -package com.jiudian.manage.until; +package com.jiudian.manage.until; // 工具类包,存放系统通用工具方法 import java.io.File; import java.io.FileOutputStream; +/** + * 文件操作工具类 + * 提供文件上传的通用方法,支撑系统中文件(如用户头像、凭证图片)的服务器存储功能 + */ public class FileUtil { + + /** + * 上传文件到服务器指定路径 + * @param file 待上传的文件字节数组(前端传递的文件会转为字节数组形式传输) + * @param filePath 服务器上的文件存储目录路径(如"D:/hotel_upload/avatar/") + * @param fileName 上传后的文件名(建议包含唯一标识,避免文件名重复覆盖) + * @return 布尔值:true=上传成功,false=上传失败(实际逻辑中当前仅返回true,异常通过throws抛出) + * @throws Exception 抛出文件操作相关异常(如IO异常、权限异常),需调用方捕获处理 + */ public static boolean uploadFile(byte[] file, String filePath, String fileName) throws Exception { + // 1. 根据存储目录路径创建File对象 File targetFile = new File(filePath); - if(!targetFile.exists()){ + + // 2. 判断存储目录是否存在,不存在则创建多级目录(mkdirs()支持创建嵌套目录,mkdir()不支持) + if (!targetFile.exists()) { targetFile.mkdirs(); } - FileOutputStream out = new FileOutputStream(filePath+fileName); + + // 3. 创建文件输出流,指定文件存储路径(目录路径 + 文件名) + FileOutputStream out = new FileOutputStream(filePath + fileName); + + // 4. 将文件字节数组写入到输出流(即写入到服务器文件) out.write(file); + + // 5. 刷新输出流,确保所有字节都被写入文件 out.flush(); + + // 6. 关闭输出流,释放IO资源(避免资源泄漏) out.close(); + + // 7. 文件写入完成,返回上传成功 return true; } -} +} \ No newline at end of file diff --git a/src/main/java/com/jiudian/manage/until/ImageCode.java b/src/main/java/com/jiudian/manage/until/ImageCode.java index ec020b1..e837110 100644 --- a/src/main/java/com/jiudian/manage/until/ImageCode.java +++ b/src/main/java/com/jiudian/manage/until/ImageCode.java @@ -9,33 +9,77 @@ import java.io.IOException; import java.io.OutputStream; import java.util.Random; +/** + * 验证码生成工具类 + * 用于生成图形验证码,支撑用户登录时的安全校验,防止恶意登录或自动化脚本攻击 + */ public class ImageCode { - public static final String CODENAME="ImageCode"; + // 验证码在HttpSession中的存储键名(固定值,登录时需通过该键名获取Session中的验证码) + public static final String CODENAME = "ImageCode"; + + /** + * 生成图形验证码并响应给前端,同时将验证码存入Session + * @param response HttpServletResponse,用于向前端输出验证码图片 + * @param session HttpSession,用于存储生成的验证码(供登录时校验) + * @throws IOException 图片写入响应流时可能抛出IO异常,需调用方处理 + */ public static void createImage(HttpServletResponse response, HttpSession session) throws IOException { + // 1. 创建 BufferedImage 对象(验证码图片载体):宽80px、高30px,RGB色彩模式 BufferedImage image = new BufferedImage(80, 30, BufferedImage.TYPE_INT_RGB); + + // 2. 获取 Graphics 对象(用于在图片上绘制内容:背景、验证码文字、干扰元素等) Graphics g = image.getGraphics(); + + // 3. 创建随机数对象(用于生成随机颜色、干扰元素位置等,增强验证码安全性) Random r = new Random(); + + // 4. 绘制验证码背景:随机颜色填充矩形(覆盖整个图片区域,宽80px、高20px) g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255))); g.fillRect(0, 0, 80, 20); - //获取生成的验证码 + + // 5. 生成4位随机验证码(数字+大写字母组合) String code = getNumber(); - //绑定验证码 + + // 6. 将生成的验证码存入Session:键为CODENAME,值为验证码,供后续登录校验使用 session.setAttribute(CODENAME, code); + + // 7. 设置验证码文字样式:无衬线字体、加粗、字号25px g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 25)); + + // 8. 设置验证码文字颜色:随机RGB颜色(与背景色区分,确保清晰可见) g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255))); + + // 9. 绘制验证码文字到图片:起始位置(x=5px,y=25px),避免文字超出图片边界 g.drawString(code, 5, 25); - //设置消息头 + + // 10. 设置响应头:指定返回内容类型为image/jpeg(告诉前端这是图片数据) response.setContentType("image/jpeg"); + + // 11. 获取响应输出流,将验证码图片以jpeg格式写入流,响应给前端 OutputStream os = response.getOutputStream(); ImageIO.write(image, "jpeg", os); } - public static String getNumber(){ + + /** + * 生成4位随机验证码(包含数字0-9和大写字母A-Z,增强验证码复杂度) + * @return 4位随机字符串(验证码内容) + */ + public static String getNumber() { + // 1. 定义验证码字符池:包含数字和大写字母,共36个字符 String str = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + // 2. 初始化验证码字符串(用于拼接最终结果) String code = ""; - for(int i= 0;i<4;i++){ - int index = (int)(Math.random()*str.length()); - code+=str.charAt(index); + + // 3. 循环4次,每次从字符池中随机选取1个字符,组成4位验证码 + for (int i = 0; i < 4; i++) { + // 生成0到str长度-1的随机索引(确保不越界) + int index = (int) (Math.random() * str.length()); + // 根据索引获取字符,拼接到验证码中 + code += str.charAt(index); } + + // 4. 返回生成的4位验证码 return code; } } diff --git a/src/main/java/com/jiudian/manage/until/State.java b/src/main/java/com/jiudian/manage/until/State.java index 422e8f6..0a4aed0 100644 --- a/src/main/java/com/jiudian/manage/until/State.java +++ b/src/main/java/com/jiudian/manage/until/State.java @@ -1,23 +1,41 @@ package com.jiudian.manage.until; -public enum State { - SuccessCode("code","0"),SuccessMessage("message","成功"), - ErrorCode("code","-1"),ErrorMessage("message","失败") - ; +/** + * 系统统一状态枚举类 + * 定义接口响应的标准状态码和提示信息,确保所有接口返回格式一致,简化前后端交互逻辑 + */ +public enum State { + // 成功状态:code=0,message=成功(用于所有业务操作成功的响应,如订单创建成功、用户登录成功) + SuccessCode("code", "0"), + SuccessMessage("message", "成功"), + // 失败状态:code=-1,message=失败(用于所有业务操作失败的通用响应,如参数错误、数据库操作失败) + ErrorCode("code", "-1"), + ErrorMessage("message", "失败"); + + // 状态对应的键名(如"code"表示状态码的键,"message"表示提示信息的键) public String name; + // 状态对应的键值(如"0"是成功状态码的值,"成功"是成功提示的值) public String message; - State(String name,String message) { + + /** + * 枚举构造方法(枚举的构造方法默认私有,仅在枚举内部创建实例时使用) + * @param name 状态键名(如"code"、"message") + * @param message 状态键值(如"0"、"成功") + */ + State(String name, String message) { this.name = name; this.message = message; } + + // 获取状态键名的getter方法(供外部访问枚举的name属性) public String getName() { return name; } + // 获取状态键值的getter方法(供外部访问枚举的message属性) public String getMessage() { return message; } - -} +} \ No newline at end of file diff --git a/src/main/java/com/jiudian/manage/until/StateSignal.java b/src/main/java/com/jiudian/manage/until/StateSignal.java index 364c9b4..17ac5dc 100644 --- a/src/main/java/com/jiudian/manage/until/StateSignal.java +++ b/src/main/java/com/jiudian/manage/until/StateSignal.java @@ -2,15 +2,39 @@ package com.jiudian.manage.until; import java.util.HashMap; +/** + * 接口响应结果封装工具类 + * 配合State枚举,统一封装接口返回的状态码、提示信息和业务数据,确保前后端交互格式一致 + */ public class StateSignal { - HashMap result = new HashMap(); + // 存储响应结果的核心容器(HashMap):key为字段名(如"code"、"message"、"data"),value为对应值 + HashMap result = new HashMap(); - public void put(State state){ - result.put(state.name,state.message); + /** + * 传入State枚举,快速添加状态码或提示信息到响应结果 + * 用于标准化添加"成功/失败"的核心状态字段(避免手动写key,减少错误) + * @param state 状态枚举(如State.SuccessCode、State.SuccessMessage) + */ + public void put(State state) { + // 将枚举的name(键名,如"code")和message(键值,如"0")存入result + result.put(state.name, state.message); } - public void put(String name,Object val){ - result.put(name,val); + + /** + * 自定义添加键值对到响应结果 + * 用于添加业务数据(如订单列表、用户信息)或自定义提示(如"验证码错误") + * @param name 自定义键名(如"data"、"errorMsg") + * @param val 对应的值(如订单List、"验证码错误,请重新输入") + */ + public void put(String name, Object val) { + result.put(name, val); } + + /** + * 获取完整的响应结果容器 + * 供Controller层调用,直接将结果返回给前端(Spring会自动转为JSON格式) + * @return 包含状态码、提示信息、业务数据的HashMap + */ public HashMap getResult() { return result; } diff --git a/src/main/java/com/jiudian/manage/until/TimeUtil.java b/src/main/java/com/jiudian/manage/until/TimeUtil.java index 297015a..140b1d4 100644 --- a/src/main/java/com/jiudian/manage/until/TimeUtil.java +++ b/src/main/java/com/jiudian/manage/until/TimeUtil.java @@ -6,38 +6,67 @@ import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +/** + * 时间操作工具类 + * 提供时间格式转换、日期差值计算的通用方法,支撑系统中时间相关业务(如订单入住天数计算、时间格式统一) + */ public class TimeUtil { + /** - * 获取两个时间段的天数从date2-date1 - * @param date1 - * @param date2 - * @return + * 计算两个日期之间的天数差(结果为 date2 - date1 的天数,支持跨年份计算) + * 用于订单金额计算(入住天数 × 房间单价 = 订单总金额) + * @param date1 起始日期字符串(格式:yyyy-MM-dd,如"2024-05-01") + * @param date2 结束日期字符串(格式:yyyy-MM-dd,如"2024-05-05") + * @return 两个日期的天数差(如上述示例返回4,表示入住4天) */ - public static int getBetweenDay(String date1, String date2) { + public static int getBetweenDay(String date1, String date2) { + // 1. 创建GregorianCalendar实例(日历对象),用于处理日期计算 Calendar d1 = new GregorianCalendar(); - d1.setTime(formatterTime(date1)); Calendar d2 = new GregorianCalendar(); + + // 2. 将传入的日期字符串转为Date类型,再设置到日历对象中 + d1.setTime(formatterTime(date1)); d2.setTime(formatterTime(date2)); + + // 3. 先计算同一年份内的天数差(结束日期的年天数 - 起始日期的年天数) int days = d2.get(Calendar.DAY_OF_YEAR) - d1.get(Calendar.DAY_OF_YEAR); - int y2 = d2.get(Calendar.YEAR); - if (d1.get(Calendar.YEAR) != y2) { + + // 4. 获取结束日期的年份,判断是否跨年份(起始年份 != 结束年份) + int endYear = d2.get(Calendar.YEAR); + if (d1.get(Calendar.YEAR) != endYear) { + // 5. 跨年份时,累加起始年份到结束年份之间每一年的总天数 do { + // 累加当前起始年份的总天数(如2023年有365天) days += d1.getActualMaximum(Calendar.DAY_OF_YEAR); + // 起始年份加1,继续计算下一年,直到起始年份等于结束年份 d1.add(Calendar.YEAR, 1); - } while (d1.get(Calendar.YEAR) != y2); + } while (d1.get(Calendar.YEAR) != endYear); } + + // 6. 返回最终的天数差 return days; } - public static Date formatterTime(String date){ + /** + * 将字符串格式的日期转为Date类型(固定格式:yyyy-MM-dd) + * 解决前端传递的日期字符串与后端Date类型不兼容的问题,统一日期格式 + * @param date 日期字符串(格式必须为yyyy-MM-dd,否则会抛出ParseException并打印异常栈) + * @return 转换后的Date对象,转换失败时返回null + */ + public static Date formatterTime(String date) { + // 1. 创建SimpleDateFormat实例,指定目标日期格式(yyyy-MM-dd) SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); - Date newDate=null; + Date newDate = null; + + // 2. 尝试解析日期字符串,捕获ParseException(格式不匹配时抛出) try { - newDate= formatter.parse(date); + newDate = formatter.parse(date); } catch (ParseException e) { + // 3. 解析失败时打印异常栈,便于排查问题(如前端传递错误格式的日期) e.printStackTrace(); } + + // 4. 返回转换后的Date对象(失败时为null) return newDate; } - -} +} \ No newline at end of file diff --git a/src/main/java/com/jiudian/manage/until/UUIDUtil.java b/src/main/java/com/jiudian/manage/until/UUIDUtil.java index 86c892d..49575a8 100644 --- a/src/main/java/com/jiudian/manage/until/UUIDUtil.java +++ b/src/main/java/com/jiudian/manage/until/UUIDUtil.java @@ -2,7 +2,12 @@ package com.jiudian.manage.until; import java.util.UUID; +/** + * UUID工具类 + * 提供短UUID生成功能,解决原生UUID过长的问题,适用于需要短唯一标识的场景(如临时ID、默认字段值) + */ public class UUIDUtil { + // 短UUID的字符池:包含小写字母、数字、大写字母,共62个字符(确保生成的标识多样性) public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", @@ -11,17 +16,30 @@ public class UUIDUtil { "W", "X", "Y", "Z" }; /** - * 生成8位UUID - * @return 8位UUID + * 生成8位长度的短UUID(基于原生UUID压缩,确保全局唯一性) + * 相比原生36位UUID更简洁,适合存储或展示在界面上 + * @return 8位随机唯一字符串(如"xY3a7B9z") */ public static String generateShortUuid() { + // 1. 创建StringBuffer,用于拼接最终的8位短UUID StringBuffer shortBuffer = new StringBuffer(); + + // 2. 生成原生UUID(36位,含"-"),并去除"-"符号,得到32位纯字母数字字符串 String uuid = UUID.randomUUID().toString().replace("-", ""); + + // 3. 循环8次,每次从32位UUID中截取4位,转换为字符池中的字符,组成8位短UUID for (int i = 0; i < 8; i++) { + // 截取4位字符串(如第1次截取0-4位,第2次截取4-8位,以此类推) String str = uuid.substring(i * 4, i * 4 + 4); + + // 将4位16进制字符串转为整数(16进制转10进制) int x = Integer.parseInt(str, 16); - shortBuffer.append(chars[x % 0x3E]); + + // 取整数对62取余(对应字符池长度),获取字符池中的索引,拼接字符 + shortBuffer.append(chars[x % 0x3E]); // 0x3E即62,与字符池长度一致 } + + // 4. 返回最终的8位短UUID return shortBuffer.toString(); } -} +} \ No newline at end of file