Spring项目中常用操作记录
List
基础操作
创建
// 使用 ArrayList(基于动态数组,适合随机访问)
List<String> arrayList = new ArrayList<>();
// 使用 LinkedList(基于链表,适合频繁插入/删除)
List<Integer> linkedList = new LinkedList<>();
// 初始化时添加元素
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
添加
list.add("D"); // 添加到末尾
list.add(0, "First"); // 插入到指定索引位置
list.addAll(otherList); // 添加另一个集合的所有元素
修改
list.set(0, "NewFirst"); // 替换指定索引的元素
删除
list.remove("A"); // 按对象删除(删除第一个匹配项)
list.remove(0); // 按索引删除
list.clear(); // 清空列表
访问
String first = list.get(0); // 获取指定索引的元素
int size = list.size(); // 获取列表长度
boolean hasA = list.contains("A"); // 判断是否包含元素
int index = list.indexOf("B"); // 查找元素的首次出现索引
遍历
// 传统 for 循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// 增强 for 循环
for (String s : list) {
System.out.println(s);
}
// Java 8+ forEach + Lambda
list.forEach(s -> System.out.println(s));
Stream API
// 过滤元素
List<String> filtered = list.stream()
.filter(s -> s.startsWith("A"))
.collect(Collectors.toList());
// 映射操作
List<Integer> lengths = list.stream()
.map(String::length)
.collect(Collectors.toList());
// 去重
List<String> distinct = list.stream()
.distinct()
.collect(Collectors.toList());
查询
多表查询
对于多表查询一般就需要使用sql
,这样操作起来更加容易
dao
@Mapper
public interface OrgDao extends BaseMapper<SysOrg> {
// 查询所有的组织数据
List<SysOrg> getOrgList(List<AdvQueryParam> advQueryParam);
}
mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.onion.boot3management.sys.org.dao.OrgDao">
<select id="getOrgList" resultType="com.onion.boot3management.sys.org.domain.SysOrg">
select *
from (select sys_org.id,
sys_org.code,
sys_org.name,
sys_org.created_at,
sys_org.updated_at,
sys_org.creator_id,
sys_org.updater_id,
sys_org.parent_id,
sys_org.remark,
creator_user.name as creator_name,
updater_user.name as updater_name
from sys_org
left join sys_user creator_user on sys_org.creator_id = creator_user.id
left join sys_user updater_user on sys_org.updater_id = updater_user.id
) res
<where>
<foreach collection="advQueryParam" item="param" separator=" AND ">
<if test="param.value!=null and param.value.size() > 0">
<choose>
<when test="param.type=='text'">
res.${param.prop} like concat('%',#{param.value[0]},'%')
</when>
</choose>
</if>
</foreach>
</where>
</select>
</mapper>
映射文件
<mapper>
标签:这是MyBatis
映射文件的根标签,namespace
属性指定了该映射文件所对应的Mapper
接口的全限定名,即com.onion.boot3management.sys.org.dao.OrgDao
。MyBatis
会通过这个命名空间将接口方法和 XML 中的 SQL 语句关联起来。
select标签
<select>
用于定义一个查询语句id
指定Mapper
接口中对应的方法名resultType
指定查询结果的映射类型(返回值类型)
where标签
where
标签用于生成sql
中的where
字句
foreach标签
advQueryParam
,对应mapper
接口中的入参collection
用于指定要遍历的集合item
用于指定集合中每个元素的别名separator
用于指定多个条件之间的关系
choose 、when标签
- 相当于
switch
和case
语句
sql查询
select *
from (select sys_org.id,
sys_org.code,
sys_org.name,
creator_user.name as creator_name,
updater_user.name as updater_name
from sys_org
left join sys_user creator_user on sys_org.creator_id = creator_user.id
left join sys_user updater_user on sys_org.updater_id = updater_user.id
) res
- 使用嵌套查询,内查询的结果命名为
res
- 使用两次左查询,从其他表中查出需要的字段
res.${param.prop} like concat('%',#{param.value[0]},'%')
res
是上面查询的结果${}
是一个占位符,会进行值的替换
sql注入的写法
这种一般可以用于固定查询条件格式的查询
service 构建查询条件
QueryWrapper<SysOrg> queryWrapper = new QueryWrapper<>();
if (!CollectionUtils.isEmpty(queryParam.getAdvQueryParam())) {
queryParam.getAdvQueryParam().forEach(item -> {
if (!CollectionUtils.isEmpty(item.getValue())) {
switch (item.getType()) {
case "text":
queryWrapper.like(item.getProp(), item.getValue().get(0));
break;
}
}
});
}
List<SysOrg> orgList = orgDao.getOrgList(queryWrapper);
dao接收
// 这里的 ew 是 QueryWrapper 对象的别名
List<SysOrg> getOrgList(@Param("ew") QueryWrapper<SysOrg> wrapper);
sql拼接
<select id="getOrgList" resultType="com.onion.boot3management.sys.org.domain.SysOrg">
select *
from (select sys_org.id,
sys_org.code,
sys_org.name,
sys_org.created_at,
sys_org.updated_at,
sys_org.creator_id,
sys_org.updater_id,
sys_org.parent_id,
sys_org.remark,
creator_user.name as creator_name,
updater_user.name as updater_name
from sys_org
left join sys_user creator_user on sys_org.creator_id = creator_user.id
left join sys_user updater_user on sys_org.updater_id = updater_user.id) res
${ew.customSqlSegment}
</select>
分页查询
基于MyBatis-Plus 实现分页查询
1、添加依赖
略
2、配置分页插件
创建一个配置类
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
3、实现
- 使用默认方法
// 创建分页对象(页码从1开始)
Page<User> page = new Page<>(pageNum, pageSize);
// 添加查询条件(可选)
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("name", "张");
// 执行查询
Page<User> result = userMapper.selectPage(page, wrapper);
- 通过
sql
,主要涉及多表查询时
// 调用`mapper`接口
public Result doPage(TableQueryParam tableQueryParam) {
// 创建Page对象,指定当前页码和每页分页记录
Page<SysFile> page = new Page<>(tableQueryParam.getPageNumber(), tableQueryParam.getPageSize());
IPage<SysFile> res = sysFileDao.doPage(page);
return Result.success(res);
}
// mapper接口
IPage<SysFile> doPage(Page<SysFile> page);
// 对应的sql
<select id="doPage" resultType="com.onion.boot3management.sys.file.domain.SysFile">
select *
from (select *
from sys_file) res
</select>
删除
根据ID批量删除
@Override
@Transactional(rollbackFor = Exception.class)
public Result batchDelete(IdList idList) {
try {
List<String> ids = idList.getIdList();
// 1、判断ID是存在
if (CollectionUtils.isEmpty(ids)) {
return Result.error("ID列表为空");
}
// 2、判断ID是否都在数据库中
LambdaQueryWrapper<SysOrg> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(SysOrg::getId, ids);
long count = orgDao.selectCount(queryWrapper);
if (count != ids.size()) {
return Result.error("部分ID不存在");
}
// 3、批量删除
orgDao.deleteBatchIds(ids);
// 4、假删除
// queryWrapper.in(SysOrg::getId, ids);
// SysOrg sysOrg = new SysOrg();
// sysOrg.setIsDel(1);
// orgDao.update(sysOrg, queryWrapper);
// 或
// LambdaUpdateWrapper<SysOrg> updateWrapper = new LambdaUpdateWrapper<>();
// updateWrapper.in(SysOrg::getId, ids).set(SysOrg::getIsDel, 1);
// orgDao.update(new SysOrg(), updateWrapper);
return Result.success();
} catch (Exception e) {
System.out.println(e.getMessage());
// 触发事务回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return Result.error("删除失败");
}
}
更新
树形数据的更新
以组织树更新为例
@Transactional(rollbackFor = Exception.class)
public Result updateOrg(OrgParam param) {
try {
// 1、判断要更新的数据是否存在
LambdaQueryWrapper<SysOrg> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysOrg::getId, param.getId());
if (!orgDao.exists(queryWrapper)) {
return Result.error("要更新的组织不存在");
}
// 2、判断上级组织是否是自己或者是子级
boolean isSelfOrChild = false;
// 字符串比较用equals
if (param.getId().equals(param.getParentId())) {
isSelfOrChild = true;
}
// 2.2 判断上级组织是否是子级
List<String> childIds = new ArrayList<>();
if (!isSelfOrChild) {
// 说明不是本身,则判断是否是子级
getChildOrgIds(param.getId(), childIds);
if (childIds.contains(param.getParentId())) {
isSelfOrChild = true;
}
}
if (isSelfOrChild) {
return Result.error("上级组织不能是本身或者子级");
}
// 3、更新上级组织、组织名称、备注、修改人、修改时间
LocalDateTime now = LocalDateTime.now();
LambdaUpdateWrapper<SysOrg> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(SysOrg::getId, param.getId())
.set(SysOrg::getParentId, param.getParentId())
.set(SysOrg::getName, param.getName())
.set(SysOrg::getRemark, param.getRemark())
.set(SysOrg::getUpdaterId, param.getUpdaterId())
.set(SysOrg::getUpdatedAt, now);
orgDao.update(new SysOrg(), updateWrapper);
return Result.success();
} catch (Exception e) {
System.out.println(e.getMessage());
// 手动回滚,避免事务无法回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return Result.error("更新失败");
}
}
/**
* 获取当前组织ID的子级、孙子级的主键
*/
private void getChildOrgIds(String parentId, List<String> childIds) {
LambdaQueryWrapper<SysOrg> queryWrapper = new LambdaQueryWrapper<>();
// 查询所有自组织
queryWrapper.eq(SysOrg::getParentId, parentId).select(SysOrg::getId);
List<SysOrg> list = orgDao.selectList(queryWrapper);
// 循环
for (SysOrg org : list) {
childIds.add(org.getId());
// 查询下一级
getChildOrgIds(org.getId(), childIds);
}
}
Controller接口的常用的入参格式
基本数据类型和包装类型作为入参
@RestController
public class BasicParamController {
@GetMapping("/basicParam")
public String getBasicParam(@RequestParam("id") Integer id) {
return "Received id: " + id;
}
}
@RequestParam
注解用于绑定请求参数到方法参数,“id” 是请求参数的名称
实体类作为入参
@RestController
public class EntityParamController {
@PostMapping("/entityParam")
public String getEntityParam(@RequestBody User user) {
return "Received user: " + user.getName() + ", age: " + user.getAge();
}
}
@RequestBody
注解用于将请求体中的 JSON
数据映射到实体类对象
表单数据作为入参
对于表单提交的数据,可以直接使用实体类或基本数据类型接收。
@PostMapping("/formData")
public String getFormData(@RequestParam("name") String name, @RequestParam("age") Integer age) {
return "Received name: " + name + ", age: " + age;
}
其他
LocalDateTime 类型的时间,返回值里有一个T
Spring Boot默认使用Jackson库序列化LocalDateTime对象时,会采用ISO-8601标准格式(如2025-02-27T10:29:26)
通过@JsonFormat
注解格式化
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") // 指定时区
private LocalDateTime updatedAt;
生成树形结构数据
public List<OrgTreeResult> buildTree(List<SysOrg> orgList) {
// 1. 将组织列表转换为Map,方便快速查找
Map<String, OrgTreeResult> orgMap = new HashMap<>();
for (SysOrg org : orgList) {
OrgTreeResult node = new OrgTreeResult();
BeanUtils.copyProperties(org, node);
// 初始化子级列表
node.setChildren(new ArrayList<>());
orgMap.put(org.getId(), node);
}
// 2. 构建树形结构
List<OrgTreeResult> rootNodes = new ArrayList<>();
for (OrgTreeResult node : orgMap.values()) {
if (node.getParentId() == null || node.getParentId().equals("-1")) {
// 如果父节点为空或为"-1",说明是根节点
rootNodes.add(node);
} else {
// 否则,找到父节点并添加到其子节点列表中
OrgTreeResult parentNode = orgMap.get(node.getParentId());
if (parentNode != null) {
parentNode.getChildren().add(node);
}
}
}
// 3. 返回根节点列表
return rootNodes;
}