当前位置: 首页 > news >正文

自己感觉好点的东西

NamedThreadFactory 命名线程工厂       ThreadPool  线程池      init()init() 方法是个静态方法,它的核心作用是:当找不到线程池配置文件时,自动创建并写入默认配置。

Properties 继承自 Hashtable,本质是一个键值对(Key-Value)存储容器,专门用于处理字符串类型的配置数据。

setProperty(String key, String value) 是 Properties 类的成员方法,作用是向 Properties 容器中添加或修改键值对配置。

FileOutputStream("MyThreadPool.properties"):创建一个文件输出流,指定目标文件为 MyThreadPool.properties(若文件不存在则自动创建,若已存在则覆盖原有内容)。

SALT_LENGTH = 16 定义为 16,表示生成的随机盐(salt)的字节长度为 16 字节,用于后续密码加盐哈希处理

generateSalt() 方法:生成随机盐
作用:生成一个随机的字节数组(盐),用于密码哈希时的 “加盐” 操作。

getParameter 用于获取客户端(如浏览器)提交的请求参数

isEmpty() 是 String 类的方法,用于判断字符串是否为空

!menId.isEmpty() 用于检查字符串 menId 是否包含有效内容,是避免空值导致逻辑错误的常用判断方式。

单独的 !menId 是语法错误(如前所述),但在 !menId.isEmpty() 中,! 并非直接作用于 menId,而是作用于 menId.isEmpty() 这个布尔表达式的结果。这是一个完整的逻辑判断,用于检查 menId 是否为非空字符串(即有实际内容)。

categoryId = Integer.parseInt(menId);  这行代码是字符串与整数类型转换的典型操作,用于将外部传入的字符串 ID 转换为程序可直接使用的整数类型,是前后端数据交互中常见的类型适配步骤。


RespData respData = null; 这行代码的作用是声明一个 RespData 类型的变量 respData 并将其初始化为 null 简言之,这行代码是对响应数据对象的初始化声明,为后续根据业务逻辑构建具体的响应结果做准备。

RoomCategory row = new CategoryServiceImp().chaById(categoryId); 这行代码的作用是通过调用服务层方法查询指定 ID 的分类数据,并将结果赋值给 RoomCategory 类型的变量 row
new CategoryServiceImp() 创建 CategoryServiceImp 类的实例。CategoryServiceImp 通常是服务层(Service)的实现类,负责封装与 “分类” 相关的业务逻辑(如数据库交互、数据校验等),是控制器(Controller)与数据访问层(DAO)之间的中间层。
.chaById(categoryId) 调用 CategoryServiceImp 实例的 chaById 方法(从方法名推测为 “根据 ID 查询”),并传入参数 categoryId(整数类型的分类 ID)。该方法的作用是根据传入的 ID 从数据源(如数据库)中查询对应的分类记录,返回一个封装了分类信息的对象
简言之,这行代码通过服务层方法查询指定 ID 的房间分类数据,并将结果存储在实体对象中,是业务逻辑中 “查询单条记录” 的典型操作。

() => {} 是 JavaScript 的箭头函数,本质是 “简化版的匿名函数”,核心作用是简化代码、绑定固定作用域,用对了能让代码更简洁,

简单记:(() => {}) 是 “一次性、独立作用域” 的工具 ——
写原生 JS、非模块化代码时,用它避免变量污染;
有只执行一次的初始化逻辑时,用它简化 “定义 + 执行”;
写 Vue/React 组件、需要复用的逻辑时,别用,用普通箭头函数或命名函数就行。

如果成功后需要再发一个请求(比如 “先查菜单列表,再查菜单详情”),可以用 .then 链式写,避免代码嵌套(俗称 “回调地狱”)

只要你用了返回 Promise 的异步操作(90% 是接口请求,比如 ajax、axios、fetch),就必须搭配 .then 和 .catch:
用 .then 接收成功数据,完成页面渲染;
用 .catch 处理所有可能的错误,避免页面崩溃、用户一脸懵。
2. 正确的使用原则
不要只写 .then 不写 .catch:万一请求失败,没处理会导致数据没赋值、页面空白,甚至控制台报错;
.catch 里必须做三件事:打印错误日志(方便调试)、重置数据(比如给空数组)、给用户提示(比如 “操作失败”);
简单逻辑可以用 async/await 替代:如果觉得 .then 链式写着麻烦,也可以用 async/await + try/catch(本质和 .then/.catch 一样,只是写法不同)

@Param 的核心价值是明确参数的标识,让 SQL 语句能清晰、准确地引用方法参数,尤其在多参数或参数为对象的场景中,能避免歧义、简化代码逻辑。

总结:是否使用 @Param 的核心区别
场景    不使用 @Param    使用 @Param
单基本类型参数    可随意命名引用(如 #{x})    必须用指定别名(如 #{status})
单对象参数    直接用 #{属性名} 引用    必须用 #{别名.属性名} 引用
多参数    需用 param1/param2 或依赖编译配置    用自定义别名引用,与顺序无关,清晰可靠
可读性与维护性    差(尤其多参数时,参数含义不明确)    好(别名直接体现参数含义)
兼容性    依赖编译配置(保留参数名),兼容性差    不依赖编译配置,兼容性好
建议:
多参数场景必须使用 @Param,避免参数顺序导致的错误;
单对象参数建议使用 @Param,通过 别名.属性名 使 SQL 更清晰;
单基本类型参数可根据习惯选择,但使用 @Param 能让代码更规范。
直观对比
类型    形态示例    核心特点    MyBatis 引用方式(不使用 @Param)
单基本类型参数    int status、String name    单一值,无属性    #{任意名称}(如 #{s}、#{x})
单对象参数    RoomCategory category    包含多个属性的实体类对象    #{属性名}(如 #{categoryName})
通过例子可以更清晰区分:
如果你传的是 1、"标准间" 这种简单值,就是基本类型参数;
如果你传的是 new RoomCategory(1, "标准间", 1) 这种包含多个字段的对象,就是对象参数。
这种多参数(含对象和基本类型)场景下,@Param 别名的作用是明确区分每个参数,映射文件中通过 别名.属性名(对象)或 别名(基本类型)引用,结合动态标签和分页逻辑,即可实现灵活的条件查询。

创建 AdminUser inputUser = new AdminUser(username, isvalid); 最核心的意义就是 “把需要操作的‘管理员用户数据’打包成一个对象”,方便后续用这个对象做查询、新增、修改等操作,不用零散传递参数。

总结:一句话记清楚
写操作(增删改):先 commit() 提交事务,再 close() 关闭 → 用 releaseWithCommit;
读操作(查):直接 close() 关闭,不提交 → 用 release;
核心原则:事务是为了保护 “数据修改” 的完整性,查询不需要事务,所以不用提交

1. protected void query(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
定义一个query方法,专门处理 “查询管理员” 的请求。
HttpServletRequest req:前端发过来的请求(包含查询条件、分页参数等)。
HttpServletResponse resp:后端要返回给前端的响应(包含查询结果)。
throws ...:声明可能抛出的异常(Servlet 和 IO 操作可能出错)。
2. req.setCharacterEncoding("utf-8");
设置请求的字符编码为utf-8,防止前端传过来的中文参数(比如用户名 “张三”)出现乱码。
3. String username = req.getParameter("username");
从请求中获取username参数(前端表单或 URL 里传的 “用户名” 查询条件,比如?username=张三)。
4. String isvalidStr = req.getParameter("isvalid");
获取isvalid参数(前端传的 “是否有效” 条件,比如?isvalid=1表示查有效用户,0表示查无效用户)。
5. String pageStr = req.getParameter("page");
获取page参数(前端传的 “当前页码”,比如?page=2表示查第 2 页)。
6. String pageSizeStr = req.getParameter("pageSize");
获取pageSize参数(前端传的 “每页条数”,比如?pageSize=10表示每页显示 10 条)。
7. Integer isvalid = null;
定义一个Integer类型的isvalid变量,用来存转换后的 “是否有效” 数值(因为前端传的是字符串,需要转成数字)。
8. if(isvalidStr!=null&&!"".equals(isvalidStr)){
判断前端是否传了isvalid参数(如果传了且不是空字符串,才需要转换)。
9. isvalid = Integer.parseInt(isvalidStr);
把前端传的字符串类型的isvalidStr(比如 “1”)转成整数类型的isvalid(比如1)。
10. }
结束if判断。
11. AdminUser inputUser = new AdminUser(username, isvalid);
创建一个AdminUser对象inputUser,把前面获取的username(用户名)和isvalid(是否有效)存进去,作为 “查询条件对象”(后续用这个对象查数据库)。
12. Integer page = 1;
定义 “当前页码” 变量page,默认值为 1(如果前端没传page参数,就查第 1 页)。
13. Integer pageSize = 3;
定义 “每页条数” 变量pageSize,默认值为 3(如果前端没传pageSize,就默认每页显示 3 条)。
14. if(pageStr!=null&&!"".equals(pageStr)){
判断前端是否传了page参数(如果传了且不为空,就用前端的页码)。
15. page = Integer.parseInt(pageStr);
把前端传的字符串类型的pageStr(比如 “2”)转成整数类型的page(比如2)。
16. }
结束page的if判断。
17. if(pageSizeStr!=null&&!"".equals(pageSizeStr)){
判断前端是否传了pageSize参数(如果传了且不为空,就用前端的每页条数)。
18. pageSize = Integer.parseInt(pageSizeStr);
把前端传的字符串类型的pageSizeStr(比如 “10”)转成整数类型的pageSize(比如10)。
19. }
结束pageSize的if判断。
20. AdminUserService adminUserService = new AdminUserServiceImpl();
创建AdminUserService的实现类对象(Service层,负责处理查询的业务逻辑)。
21. Integer total = adminUserService.countUser(inputUser);
调用Service的countUser方法,根据inputUser的条件,查询符合条件的管理员 “总记录数”(比如符合条件的有 12 条)。
22. Integer totalPage = PageInfo.getTotalPage(total, pageSize);
调用工具类PageInfo的getTotalPage方法,根据 “总记录数” 和 “每页条数”,计算 “总页数”(比如 12 条 ÷ 每页 3 条 = 4 页)。
23. if(totalPage!=0&&page>totalPage){
判断:如果总页数不为 0(有数据),且前端传的页码page大于总页数(比如总页数 4,前端传了 5),就需要校正页码。
24. page = totalPage;
把页码改成总页数(比如前端传 5,总页数 4,就自动查第 4 页,避免查不到数据)。
25. }
结束页码校正的if判断。
26. List<AdminUser> adminUsers = adminUserService.listUserByCondition(inputUser, page, pageSize);
调用Service的listUserByCondition方法,根据条件inputUser、页码page、每页条数pageSize,查询当前页的管理员列表数据(比如第 2 页的 3 条数据)。
27. ReturnResult returnResult = new ReturnResult();
创建一个ReturnResult对象(统一的返回结果封装类,包含状态码、提示信息、数据等)。
28. if(adminUsers.size()>0){
判断:如果查询到的管理员列表不为空(有数据)。
29. returnResult.setCode(ReturnCode.QUERY_SUCCESS.getCode());
给返回结果设置 “查询成功” 的状态码(比如200,前端根据这个码知道成功了)。
30. returnResult.setMsg(ReturnCode.QUERY_SUCCESS.getMsg());
设置 “查询成功” 的提示信息(比如 “查询成功”,前端可以显示给用户)。
31. returnResult.setReturnData(adminUsers);
把查询到的管理员列表数据adminUsers存到返回结果里(前端要显示的具体数据)。
32. PageInfo pageInfo = new PageInfo(page,pageSize,total);
创建PageInfo对象,封装分页信息(当前页、每页条数、总记录数),方便前端做分页控件(比如显示 “第 2 页 / 共 4 页”)。
33. returnResult.setPageInfo(pageInfo);
把分页信息存到返回结果里。
34. }
结束 “有数据” 的if判断。
35. else{
如果查询到的管理员列表为空(没数据)。
36. returnResult.setCode(ReturnCode.QUERY_NODATA.getCode());
设置 “查询无数据” 的状态码(比如201)。
37. returnResult.setMsg(ReturnCode.QUERY_NODATA.getMsg());
设置 “查询无数据” 的提示信息(比如 “未查询到数据”)。
38. }
结束else判断。
39. resp.setContentType("application/json;charset=utf-8");
设置响应的格式为JSON,字符编码utf-8(告诉前端 “我返回的是 JSON 数据,且中文不会乱码”)。
40. PrintWriter writer = resp.getWriter();
获取响应的输出流(用来把数据写给前端)。
41. writer.print(JSON.toJSONString(returnResult));
把returnResult对象转成 JSON 字符串(比如{"code":200,"msg":"查询成功","data":[...]}),并通过输出流发给前端。
42. writer.close();
关闭输出流,释放资源。
43. }
结束query方法。
总结
整个方法的流程就是:接收前端参数→处理参数(转类型、设默认值)→查总记录数→算总页数→校正页码→查当前页数据→封装结果(成功 / 失败 + 数据 + 分页信息)→返回 JSON 给前端。核心是 “按前端的条件和分页要求,查数据并返回标准化结果”

1. Map<String, Object> dataMap = new HashMap<>();
作用:创建一个 “键值对容器”(dataMap),用来装要返回给前端的 “具体数据”(比如总记录数、管理员列表)。
大白话:就像准备一个快递盒子,盒子里要放 “总共有多少人”(total)和 “具体是哪些人”(UserList)这两样东西,后续把盒子一起打包发给前端。
2. if (!adminUsers.isEmpty()) {
作用:判断之前查询到的管理员列表(adminUsers)是不是 “非空”(也就是有没有查到数据)。
大白话:检查 “管理员列表” 里有没有内容 —— 有内容就走 “查询成功” 的逻辑,没内容就走 “查询失败(无数据)” 的逻辑。
3. dataMap.put("total", userCount);
作用:往dataMap里放 “总记录数”—— 键是"total"(前端能通过这个键拿到总数量),值是userCount(之前统计的符合条件的管理员总数,比如 12)。
大白话:在快递盒子里放一张纸条,纸条上写着 “total”,后面跟着数字 12,告诉前端 “符合条件的管理员一共有 12 个”。
4. dataMap.put("UserList", adminUsers);
作用:往dataMap里放 “管理员列表数据”—— 键是"UserList"(前端用这个键拿列表),值是adminUsers(实际查询到的管理员对象列表,比如包含 “张三”“李四” 的列表)。
大白话:在快递盒子里再放一份 “管理员名单”,名单标签写着 “UserList”,里面是具体的管理员信息(姓名、ID、状态等)。
5. respData = new RespData(RespSendStatus.GETUSERLIST_SUCCESS.getCode(), RespSendStatus.GETUSERLIST_SUCCESS.getMessage(), dataMap);
作用:创建一个 “统一响应对象”(respData),把 “状态码”“提示信息”“具体数据(dataMap)” 打包在一起。
大白话:把前面准备好的 “快递盒子(dataMap)”,再装进一个 “标准快递袋”—— 袋子上印着 “成功码(比如 200)” 和 “提示语(比如‘查询管理员列表成功’)”,方便前端一看就知道 “这次请求成功了,数据在里面”。
补充:RespSendStatus是自定义的 “状态枚举类”,里面存着各种请求状态(成功、失败)的代码和提示信息,不用手动写字符串,避免写错。
6. } else {
作用:如果adminUsers是空的(没查到数据),就走这个 “else 分支”。
7. dataMap.put("total", 0);
作用:没查到数据时,往dataMap里放 “总记录数 0”—— 告诉前端 “符合条件的管理员数量是 0”。
8. dataMap.put("UserList", adminUsers);
作用:把空的adminUsers(空列表)放进dataMap—— 前端拿到后能看到 “列表是空的”,而不是没这个键。
9. respData = new RespData(RespSendStatus.GETUSERLIST_FAILED.getCode(), RespSendStatus.GETUSERLIST_FAILED.getMessage(), dataMap);
作用:创建 “失败的统一响应对象”—— 状态码是 “失败码(比如 201)”,提示语是 “查询管理员列表失败(无数据)”,数据还是空的dataMap。
大白话:装一个 “失败的标准快递袋”,袋子上印着 “失败码” 和 “没查到数据” 的提示,前端一看就知道 “没查到数据,不用解析列表了”。
10. }
作用:结束if-else判断(不管成功还是失败,到这里就完成了 “响应对象” 的封装)。
11. PrintWriter writer = resp.getWriter();
作用:从响应对象(resp)里获取一个 “输出流”(writer)—— 相当于打开 “给前端发消息的通道”。
大白话:准备一个 “打印机”,后续要把 “标准快递袋(respData)” 转成前端能看懂的 “JSON 字符串”,再用这个 “打印机” 发给前端。
12. writer.print(JSON.toJSONString(respData));
作用:把 “统一响应对象(respData)” 转成 JSON 字符串,再通过输出流发给前端。
大白话:用 “打印机” 把 “标准快递袋” 上的所有信息(状态码、提示语、dataMap 里的总记录数和列表),转成前端能解析的 “JSON 格式字符串”(比如{"code":200,"msg":"查询成功","data":{"total":12,"UserList":[...]}}),然后发过去。
13. writer.close();
作用:关闭输出流,释放资源。
大白话:“打印机” 用完后关掉,避免一直占用 “通道”,导致资源浪费。
总结
这几行代码的核心逻辑就是:先判断有没有查到数据 → 有数据就装 “成功包”,没数据就装 “失败包” → 把包转成 JSON 发给前端。目的是让前端能拿到 “格式统一、含义清晰” 的结果,不用猜 “这次请求是成功还是失败,数据在哪”。


// 后端Cate方法中,查询到列表后:
List<RoomCategory> roomCategories = categoryServiceImp.listCategory(roomCategory, page, pageSize);

// 构建返回结果时,把列表放进data字段
if (roomCategories != null && !roomCategories.isEmpty()) {
// 成功时:code=200,message=成功信息,data=列表数据
respData = new RespData(
RespSendStatus.GETUSERLIST_SUCCESS.getCode(),
RespSendStatus.GETUSERLIST_SUCCESS.getMessage(),
roomCategories  // 关键:把房间分类列表作为data传入
);
} else {
// 失败时:至少返回空列表,避免前端报错
respData = new RespData(
RespSendStatus.GETUSERLIST_FAILED.getCode(),
RespSendStatus.GETUSERLIST_FAILED.getMessage(),
new ArrayList<>()  // 空列表
);
}

</el-table>
原理:formatter 函数接收当前行数据 row,如果 row.categoryLogo 为空(或不存在),就返回 “无”,否则显示实际值。

<template>:Vue 中的模板标签,用于定义可复用的 HTML 片段。

#default:这是 Vue 的 “具名插槽” 语法(# 是 v-slot: 的简写),default 表示 “默认插槽”。在 Element Plus 的 el-table-column 中,默认插槽用于自定义该列的单元格内容
="scope":scope 是插槽的 “作用域变量”,包含了当前行的数据、行索引等信息(由 el-table 自动传递给插槽)。
<el-tag>{{ scope.row.categoryName }}</el-tag>
<el-tag>:Element Plus 的标签组件,用于展示带背景色的文本(类似标签样式,比普通文字更醒目)。
{{ scope.row.categoryName }}:
scope.row 表示当前行的数据对象(比如表格数据中的 {categoryId: 2, categoryName: '音乐综合', ...})。
categoryName 是当前行对象中的字段名,这里会显示该字段的值(比如 音乐综合、派单 等)。
实际效果:
假设原来这一列直接显示文字 音乐综合,用了这段模板后,会变成一个带背景色的标签(类似 🏷️ 音乐综合),让分类名称更突出。

http://www.dtcms.com/a/569203.html

相关文章:

  • 计算机网络自顶向下方法30——运输层 网络拥塞控制中的公平性
  • 专门做隐形眼镜的网站seo的中文含义是什么意思
  • O2O行业风口下的运营策略与定制开发AI智能名片S2B2C商城小程序的应用研究
  • 新建代码仓库后,初始化仓库
  • 龙川做网站的wordpress 文章折叠
  • Glances服务器硬件资源监控工具
  • Docker(三)_容器打包
  • 专业做网站有哪些上海机械网站建设
  • Spring Boot异步接口性能优化:从单线程到高并发的优化历程
  • App通信:HTTP与JSON全解析
  • 网站推广什么意思资料网站怎么做的
  • win10本地部署weknora记录
  • 7、webgl 基本概念 + 前置数学知识点(向量 + 矩阵)
  • 寻花问柳专做男人的网站高端网站建设设计公司哪家好
  • Rust开发实战之RESTful API客户端开发
  • C++ 锁类型大全详解
  • 智慧园区:智能管理赋能未来发展新生态
  • 潮州 网站建设个人静态网站首页怎么做
  • 东莞网站建站推广wordpress导入演示数据
  • socket_udp
  • 基于单片机的智能家居窗帘控制系统设计(论文+源码)
  • Nestjs框架: 微服务架构拆分原则与实战指南
  • WinSCP的简单使用与SFTP自动备份 .bat脚本
  • iOS 虚拟位置设置实战,多工具协同打造精准调试与场景模拟环境
  • Qt 全球峰会 2025:中国站速递 —— 技术中立,拥抱更大生态
  • Android集成Unity避坑指南
  • 我的网站设计联盟网站推广营销应该怎么做
  • 从零开始刷算法-栈-括号匹配
  • 走进Linux的世界:初识进程(Task)
  • 首钢建设集团山东公司网站2017年网站建设公司