智慧社区构建——2

1.实现Token校验

## Token校验URL```json
GET /checkToken
```参数```json
HttpServletRequest request
```返回```json
{"msg": "操作成功","code": 200,"status": "ok"
}{"msg": "操作成功","code": 200,"status": "error"
}

 在LoginController中实现下面得方法

/*** Token校验* @param request HTTP请求* @return 校验结果*/@RequestMapping("/checkToken")public Result checkToken(HttpServletRequest request) {//1.从请求头中获取tokenString token = request.getHeader("token");System.out.println("从请求头获取到的token:" + token);//2.判断token是否为空或空字符串,如果是则返回错误信息if (token == null || token.isEmpty()) {System.out.println("token为空或空字符串,验证失败");return Result.ok().put("status", "error").put("msg", "token不能为空");}//3.声明变量用于标记JWT格式是否有效boolean isJwtValid;//4.声明变量用于存储从token中解析出的userIdString userId = null;try {//5.使用JWT工具类解析token,获取负载信息Claims claims = Jwts.parser().setSigningKey(jwtUtil.getSecret()).parseClaimsJws(token).getBody();//6.从负载中获取userIduserId = claims.get("userId", String.class);System.out.println("从token中解析出的userId:" + userId);//7.如果解析成功,标记JWT格式有效isJwtValid = true;System.out.println("JWT格式验证通过");} catch (Exception e) {//8.如果解析失败,标记JWT格式无效isJwtValid = false;System.out.println("JWT格式验证失败,异常信息:" + e.getMessage());}//9.如果JWT格式无效,返回错误信息if (!isJwtValid) {System.out.println("JWT格式无效,返回错误响应");return Result.ok().put("status", "error").put("msg", "token格式无效");}//10.根据userId拼接Redis中存储token的keyString redisKey = "communityuser-" + userId;System.out.println("Redis中存储token的key:" + redisKey);//11.从Redis中获取存储的tokenString redisToken = (String) redisTemplate.opsForValue().get(redisKey);System.out.println("从Redis中获取到的token:" + redisToken);//12.判断Redis中是否存在token且与请求中的token一致boolean isTokenValid = redisToken != null && redisToken.equals(token);System.out.println("Redis中token与请求token是否一致:" + isTokenValid);//13.根据双重验证结果返回对应的响应信息if (isTokenValid) {System.out.println("token双重验证通过,返回成功响应");return Result.ok().put("status", "ok").put("msg", "token验证通过");} else {System.out.println("token双重验证失败,返回错误响应");return Result.ok().put("status", "error").put("msg", "token已失效或不匹配");}}

利用上面得Token校验实现动态路由

加载动态路由

实现思路

1.通过session获取用户信息

2.根据userId获取角色名称,需要在user_role表和role表中联表查询

3.根据userId获取用户的权限菜单:

第一步:根据用户的id查询该用户所对应的角色以及该角色所对应的菜单,需要user_role、user_menu、menu三个表联表查询;

第二步:按照查询出来的菜单进行封装,一个一级菜单的信息封装进一个列表,此菜单下的二级菜单的信息封装进此列表的子列表中,若有三级菜单以此类推进行封装

④返回用户信息、角色名称和用户的权限菜单信息,格式如

```json
{"msg": "操作成功","code": 200,"data": {"userId": 1,"username": "admin", "password": "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92","realName": "管理员", "contact": "", "mobile": "15679711120", "status": 1},"roles": "超级管理员","routers": [{"name": "系统管理","path": "/sys","hidden": "false","redirect": "noRedirect","component": "Layout","alwaysShow": true,"meta": {"title": "系统管理","icon": "system"},"children": [{"name": "管理员管理","path": "/user","hidden": "false","component": "sys/user/index","meta": {"title": "管理员管理","icon": "user"}}]}]
}

封装返回的routers信息MenuRouterVO、ChildMenuRouterVO、MenuRouterVO

package com.qcby.vo;import lombok.Data;import java.util.List;@Data
public class MenuRouterVO {private String name;private String path;private String component;private String hidden;private String redirect = "noRedirect";private Boolean alwaysShow = true;private MetaVO meta;private List<ChildMenuRouterVO> children;}
package com.qcby.vo;import lombok.Data;@Data
public class ChildMenuRouterVO {private String name;private String path;private String component;private String hidden;private MetaVO meta;}
package com.qcby.vo;import lombok.Data;@Data
public class MetaVO {private String title;private String icon;
}

加载动态路由controller请求

/*** 通过登录的用于加载动态路由* 显示该用户能访问的菜单* @param session* @return*/@RequestMapping("/getRouters")public Result getRouters(HttpSession session){//获取用户名称User user = (User)session.getAttribute("user");//获取用户的角色名称String roles = roleMapper.getRoleNameByUserId(user.getUserId());//获取用户的权限菜单List<MenuRouterVO> routers = this.menuService.getMenuRouterByUserId(user.getUserId());return Result.ok().put("data", user).put("roles", roles).put("routers",routers);}

获取用户的角色名称的mapper

@Select("SELECT role_name FROM role, user_role where user_role.role_id=role.role_id and user_role.user_id=#{userId}")public String getRoleNameByUserId(Integer userId);

获取用户的菜单信息service

 /*** 重写接口方法,根据用户ID获取菜单路由信息* @param userId 用户ID* @return 菜单路由信息列表*/@Overridepublic List<MenuRouterVO> getMenuRouterByUserId(Integer userId) {// 1. 根据用户ID查询该用户拥有的角色及对应的所有菜单列表List<Menu> menuList = this.menuMapper.getMenusByUserId(userId);// 2. 创建最终要返回的菜单路由VO集合(VO用于前端展示的数据模型)List<MenuRouterVO> list = new ArrayList<>();// 3. 遍历所有菜单,筛选出一级菜单(父菜单ID为0)并封装成MenuRouterVOfor (Menu menu : menuList) {// 筛选一级菜单(parentId为0表示是顶级菜单)if (menu.getParentId() == 0) {// 创建一级菜单路由VO对象MenuRouterVO menuRouterVO = new MenuRouterVO();// 复制Menu对象的属性到MenuRouterVO(使用框架提供的属性拷贝工具类)BeanUtils.copyProperties(menu, menuRouterVO);// 封装Meta信息(前端显示需要的标题和图标)MetaVO metaVO = new MetaVO();metaVO.setTitle(menu.getName()); // 设置菜单标题metaVO.setIcon(menu.getIcon()); // 设置菜单图标menuRouterVO.setMeta(metaVO); // 将meta信息设置到路由对象// 获取当前一级菜单的ID,用于匹配其子菜单Integer menuId = menu.getMenuId();// 4. 创建子菜单集合,用于存储当前一级菜单下的所有子菜单List<ChildMenuRouterVO> children = new ArrayList<>();// 遍历所有菜单,筛选出属于当前一级菜单的子菜单for (Menu child : menuList) {// 判断当前菜单是否为当前一级菜单的子菜单(子菜单的parentId等于父菜单的menuId)if(child.getParentId() == menuId){// 5. 创建子菜单路由VO对象并封装数据ChildMenuRouterVO childVO = new ChildMenuRouterVO();BeanUtils.copyProperties(child, childVO); // 复制基本属性// 封装子菜单的Meta信息MetaVO childMetaVO = new MetaVO();childMetaVO.setTitle(child.getName()); // 子菜单标题childMetaVO.setIcon(child.getIcon()); // 子菜单图标childVO.setMeta(childMetaVO); // 设置子菜单的meta信息// 将子菜单添加到子菜单集合children.add(childVO);}}// 6. 将子菜单集合设置到当前一级菜单路由对象中menuRouterVO.setChildren(children);// 7. 将封装好的一级菜单路由对象添加到最终返回的集合中list.add(menuRouterVO);}}// 返回整理好的菜单路由列表(包含一级菜单和对应的子菜单)return list;}

获取用户的菜单信息mapper

    @Select({"select m.menu_id,m.parent_id,m.name,m.path,m.component," +"m.menu_type,m.status,m.icon,m.sort,m.hidden from " +"user_role ur,role_menu rm,menu m where ur.role_id = rm.role_id" +" and rm.menu_id = m.menu_id " +"and ur.user_id = #{userId} order by m.sort"})public List<Menu> getMenusByUserId(Integer userId);

结果图

登录进去之后就能够看到一级目录

每个目录下面有对应得子目录

2.修改密码

实现思路

①发送更新密码请求,弹出更新密码弹出层

②前端密码格式验证,新旧密码是否一致验证

③修改密码:第一步获取session中的用户信息;第二步将根据用户查询的密码和前端传来的旧密码进行比较,如果相等,将新密码加密后在数据库中更新密码字段信息,密码更新成功,返回。

修改密码请求处理

/*** 修改用户密码的控制器方法* @return 返回操作结果*/@PutMapping("/updatePassword")  // 使用PUT映射处理/updatePassword请求public Result updatePassword(@RequestBody UpdatePasswordFrom updatePasswordFrom, HttpSession session){// 从session中获取当前登录的用户信息User user = (User)session.getAttribute("user");// 获取用户当前存储的密码String pwd = user.getPassword();// 使用SHA-256算法对用户输入的原密码进行加密String password = SecureUtil.sha256(updatePasswordFrom.getPassword());// 比较数据库中的密码和用户输入的原密码是否一致if(pwd.equals(password)){String newpassword = SecureUtil.sha256(updatePasswordFrom.getNewPassword());user.setPassword(newpassword);if(userService.updateById(user)){return Result.ok().put("status","success");}return Result.error("修改失败");}
// 原密码验证失败return Result.ok().put("status","passwordError");}

密码修改表单实体类UpdatePasswordFrom

package com.qcby.DTO;import lombok.Data;/*** 密码修改表单实体类* 用于接收前端传递的旧密码修改相关参数*/
@Data
public class UpdatePasswordFrom {/*** 当前密码(旧密码)*/private String password;/*** 新密码*/private String newPassword;/*** 确认新密码(可选,用于前端二次验证)*/private String confirmPassword;
}

 结果

3.退出登录模块

实现思路

①登出请求:将当前session设置为无效

②将token设置为空

③将router设置为空

④将cookie里面的token信息清空

⑤返回登录页面

登出请求处理

 /*** 用户退出* @param session* @return*/@RequestMapping("/logout")public Result logOut(HttpSession session){session.invalidate();return Result.ok();}

结果图

4.小区的增删改查

对应的实体类

package com.qcby.entity;import lombok.Data;import java.util.Date;@Data
public class Community {private Integer communityId;private String communityName;private Integer termCount;private Integer seq;private String creater;private Date createTime;private Float lng;private Float lat;
}

服务层

package com.qcby.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.qcby.DTO.CommunityListFrom;
import com.qcby.entity.Community;
import com.qcby.vo.PageVO;public interface ICommunityService extends IService<Community> {PageVO communityList(CommunityListFrom communityListForm);
}

增删改查的实现思路 

对于传入参数,如果有,但是参数不多,只有一个,直接接收;如果参数较多,应将其传入字段封装在一个实体类中。对于get请求,用@PathVariable接收,对于非get请求,用@RequestBody接收。

对于返回参数,如果与数据单表中的字段可以进行一一映射,不需要考虑封装,直接返回;如果无法在单表中进行一一映射,则需要根据返回参数进行实体类封装。

对于单表的增删改查,mybatiaPlus提供了相应的操作,对于多表则需要手写sql语句

4.1小区搜索和查询

传入参数

{"page": 1,"limit": 10,"communityId": "","communityName": ""
}

返回参数

{"msg": "操作成功","code": 200,"data": {"totalCount": 8,"pageSize": 10,"totalPage": 1,"currPage": 1,"list": [{"communityId": 19,"communityName": "北清云际","termCount": 33,"seq": 190,"creater": "admin","createTime": "2023-07-18 00:41:20","lng": 116.298904,"lat": 40.091644,"personCnt": 1},{"communityId": 17,"communityName": "天龙苑","termCount": 10,"seq": 170,"creater": "admin","createTime": "2023-07-18 00:38:06","lng": 116.36206,"lat": 40.088108,"personCnt": 0}]}
} 

 实现思路:由于返回list中在community表中没有personCnt字段,因此需要封装一个CommunityVO类用于数据的返回。同时由于mybtisPlus中并没有现成的sql用于根据community_id查询相应的居民人数,因此需要编写sql用来查询每个community对于的人数personCnt

CommunityVO类

package com.qcby.vo;import lombok.Data;import java.util.Date;@Data
public class CommunityVO {private Integer communityId;private String communityName;private Integer termCount;private Integer seq;private String creater;private Date createTime;private Float lng;private Float lat;private Integer personCnt;
}

 controller

/*** 获取小区的所有信息,分页条件查询* @return*/@GetMapping("/list")public Result getList(CommunityListFrom communityListFrom){PageVO pageVO = this.communityService.communityList(communityListFrom);return Result.ok().put("data",pageVO);}

service 

// CommunityServiceImpl.java
package com.qcby.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcby.DTO.CommunityListFrom;
import com.qcby.entity.Community;
import com.qcby.mapper.CommunityMapper;
import com.qcby.service.ICommunityService;
import com.qcby.vo.CommunityVO;
import com.qcby.vo.PageVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;@Service
public class CommunityServiceImpl extends ServiceImpl<CommunityMapper, Community> implements ICommunityService {@Autowiredprivate CommunityMapper communityMapper;@Overridepublic PageVO communityList(CommunityListFrom communityListForm) {Page<Community> page = new Page<>(communityListForm.getPage(), communityListForm.getLimit());QueryWrapper<Community> queryWrapper = new QueryWrapper<>();queryWrapper.like(StringUtils.isNotBlank(communityListForm.getCommunityName()), "community_name", communityListForm.getCommunityName());Page<Community> resultPage = this.communityMapper.selectPage(page, queryWrapper);PageVO pageVO = new PageVO();List<CommunityVO> list = new ArrayList<>();for (Community record : resultPage.getRecords()) {CommunityVO communityVO = new CommunityVO();BeanUtils.copyProperties(record, communityVO);Integer personCount = communityMapper.getCountByCommunityId(record.getCommunityId());communityVO.setPersonCnt(personCount);list.add(communityVO);}pageVO.setList(list);pageVO.setTotalCount(resultPage.getTotal());pageVO.setPageSize(resultPage.getSize());pageVO.setCurrPage(resultPage.getCurrent());pageVO.setTotalPage(resultPage.getPages());return pageVO;}
}

 根据communityId查询居民人数的mapper

@Select({"select count(*) from person where community_id = #{communityId} "})Integer getCountByCommunityId(Integer communityId);

分页 

用于分页封装的实体类
package com.qcby.vo;import lombok.Data;import java.util.List;@Data
public class PageVO {private Long totalCount;private Long totalPage;private Long pageSize;private Long currPage;private List list;
}
分页的相关配置 
package com.qcby.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MyBatisPlusConfig {/*** 配置分页插件*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 添加分页拦截器(支持MySQL、PostgreSQL等主流数据库)interceptor.addInnerInterceptor(new PaginationInnerInterceptor());//添加乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}
}

结果图

4.2添加小区

传入参数

{"communityName": "test""lat": "1""lng": "1""seq": 1"termCount": "1"
}

返回参数

 {"msg": "操作成功","code": 200
}

controller

 /*** 添加小区* @param community* @param session* @return*/@RequestMapping("/add")public Result add(@RequestBody Community community, HttpSession session){User user = (User) session.getAttribute("user");community.setCreater(user.getUsername());boolean save = this.communityService.save(community);if(!save) return Result.error("添加失败");return Result.ok();}

界面

4.3通过id查询小区

传入参数

1

返回参数

{"msg": "操作成功","code": 200,"data": {"communityId": 19,"communityName": "北清云际","termCount": 33,"seq": 190,"lng": 116.298904,"lat": 40.091644}
}

controller

 /*** 修改的回显操作* @param id* @return*/@RequestMapping("/info/{id}")public Result info(@PathVariable("id") Integer id){Community community = this.communityService.getById(id);if(community == null){return Result.error("没有此小区");}return Result.ok().put("data",community);}

界面

 4.4修改小区

传入参数

{"communityId": 21,"communityName": "1","termCount": "12","lng": "12","lat": "12","seq": 210
}

返回参数

{"msg": "操作成功","code": 200
}

controller

/*** 修改小区信息* @param community* @return*/@RequestMapping("/edit")public Result edit(@RequestBody Community community){boolean updateById = this.communityService.updateById(community);if(!updateById) return Result.error("修改失败");return Result.ok();}

界面

4.5删除小区

传入参数

[21,20
]

返回参数

{"msg": "操作成功","code": 200
}

controller

   /*** 仅删除小区信息,不删除关联表数据(不使用try-catch)* @param ids 小区ID数组* @return 操作结果*/@RequestMapping("/del")@Transactionalpublic Result del(@RequestBody Integer[] ids) {// 删除小区数据boolean remove = this.communityService.removeByIds(Arrays.asList(ids));if (!remove) {return Result.error("小区删除失败");}return Result.ok();}

界面

注意:在删除小区的同时也会删除掉这个小区对应的摄像头、访客记录、小区出入记录、小区居民,如果数据库中没有则会个小区对应的内容则会删除失败

5.摄像头的增删改查

和上面的小区的实现基本一致

对应的Controller

package com.qcby.controller;import com.qcby.entity.Camera;
import com.qcby.entity.User;
import com.qcby.service.ICameraService;
import com.qcby.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.List;@RestController
@RequestMapping("/sys/camera")
public class CameraController {@Autowiredprivate ICameraService cameraService;/*** 查询摄像头列表*/@GetMapping("/list/{communityId}")public Result getCameraList(@PathVariable Integer communityId) {try {// 调用关联查询方法,获取包含小区名称的摄像头列表List<Camera> cameraList = cameraService.getCameraListWithCommunityName(communityId);return Result.ok().put("data", cameraList);} catch (Exception e) {return Result.error("查询失败:" + e.getMessage());}}/*** 添加摄像头*/@RequestMapping("/add")public Result add(@RequestBody Camera camera, HttpSession session){User user = (User) session.getAttribute("user");camera.setCreater(user.getUsername());boolean save = cameraService.save(camera);if(!save) return Result.error("添加失败");return Result.ok();}/*** 修改的回显操作* @param id* @return*/@RequestMapping("/info/{id}")public Result info(@PathVariable("id") Integer id){Camera camera = cameraService.getById(id);if(camera == null){return Result.error("没有此摄像头");}return Result.ok().put("data",camera);}/*** 修改摄像头信息* @param camera* @return*/@RequestMapping("/edit")public Result edit(@RequestBody Camera camera){boolean updateById = cameraService.updateById(camera);if(!updateById) return Result.error("修改失败");return Result.ok();}/*** 删除摄像头信息* @param ids 摄像头ID数组* @return 操作结果*/@RequestMapping("/del")public Result del(@RequestBody Integer[] ids){boolean remove = cameraService.removeByIds(Arrays.asList(ids));if(!remove) return Result.error("删除失败");return Result.ok();}
}

对应的实体类

package com.qcby.entity;import lombok.Data;@Data
public class Person {private Integer personId;private Integer communityId;private String termName;private String houseNo;private String userName;private String sex;private String mobile;private String faceUrl;private String personType;private Integer state;private String creater;private String createTime;private String remark;private String faceBase;
}

对应的Mapper.java

package com.qcby.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qcby.entity.Camera;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Param;
import java.util.List;public interface CameraMapper extends BaseMapper<Camera> {// 联表查询,通过 camera 的 community_id 关联 community 表,获取小区名称@Select("SELECT c.*, com.community_name as communityName " +"FROM camera c " +"LEFT JOIN community com ON c.community_id = com.community_id " +"WHERE c.community_id = #{communityId}")List<Camera> selectCameraWithCommunityName(@Param("communityId") Integer communityId);
}

应的Mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qcby.mapper.CameraMapper"><!-- 与数据库表字段严格映射 --><resultMap id="BaseResultMap" type="com.qcby.entity.Camera"><id column="camera_id" property="cameraId" /><result column="community_id" property="communityId" /><result column="camera_name" property="cameraName" /><result column="mac_id" property="macId" /><result column="direction" property="direction" /><result column="state" property="state" /><result column="seq" property="seq" /><result column="creater" property="creater" /><result column="create_time" property="createTime" /><result column="remark" property="remark" /></resultMap><!-- 完整查询字段列表 --><sql id="Base_Column_List">camera_id,community_id,camera_name,mac_id,direction,state,seq,creater,create_time,remark</sql><!-- selectById 实现(MyBatis-Plus 基础方法) --><select id="selectById" resultMap="BaseResultMap">SELECT<include refid="Base_Column_List" />FROM cameraWHERE camera_id = #{id}</select><!--修改摄像头信息--><update id="updateById" parameterType="com.qcby.entity.Camera">UPDATE camera<set><if test="et.cameraName != null">camera_name = #{et.cameraName},</if><if test="et.macId != null"> mac_id = #{et.macId},</if><if test="et.direction != null"> direction = #{et.direction},</if><if test="et.state != null"> state = #{et.state},</if><if test="et.seq != null"> seq = #{et.seq},</if><if test="et.remark != null"> remark = #{et.remark},</if></set>WHERE camera_id = #{et.cameraId}</update><!--删除摄像头--><delete id="deleteBatchIds" parameterType="java.util.Collection">DELETE FROM cameraWHERE camera_id IN<foreach item="id" collection="coll" separator="," open="(" close=")">#{id}</foreach></delete>
</mapper>

对应的ICameraService

package com.qcby.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.qcby.entity.Camera;import java.util.List;public interface ICameraService extends IService<Camera> {List<Camera> getCameraListWithCommunityName(Integer communityId);
}

对应的CameraServiceImpl

package com.qcby.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcby.entity.Camera;
import com.qcby.mapper.CameraMapper;
import com.qcby.service.ICameraService;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class CameraServiceImpl extends ServiceImpl<CameraMapper, Camera> implements ICameraService {@Overridepublic List<Camera> getCameraListWithCommunityName(Integer communityId) {return baseMapper.selectCameraWithCommunityName(communityId);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/91468.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/91468.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

K-Means聚类:当数据没有标签时,如何让计算机自动“物以类聚”?

K-Means聚类&#xff1a;当数据没有标签时&#xff0c;如何让计算机自动“物以类聚”&#xff1f;&#x1f44b; 大家好&#xff0c;我是小瑞瑞&#xff01;欢迎回到我的专栏&#xff01; 在我们之前的旅程中&#xff0c;解决的问题大多都有一个明确的“目标”&#xff0c;比如…

万事皆可用 GeeLark AI

在今年4月&#xff0c;GeeLark AI 全面接入 DeepSeek AI 大模型&#xff0c;你可以在独立窗口中便捷地使用 GeeLark AI。除了帮助你编写文案等基础内容&#xff0c;在使用 GeeLark 过程中&#xff0c;如果遇到问题&#xff0c;也可以通过询问 GeeLark AI&#xff0c;及时获取帮…

3D 高保真处理:声网让游戏声音随角色动作变化

传统游戏的声音体验像老式收音机&#xff0c;不管声源位置、距离和障碍物&#xff0c;仅靠左右声道机械调音量&#xff0c;毫无方向感和空间感&#xff0c;如同蒙眼听声辨位。射击游戏中敌人从左边来&#xff0c;耳机却两边同响且音量相近&#xff0c;让人晕头转向&#xff1b;…

Nestjs框架: 请求生命周期与应用生命周期

概述 在 NestJS 框架中&#xff0c;中间件&#xff08;Middleware&#xff09;、管道&#xff08;Pipes&#xff09;、过滤器&#xff08;Filters&#xff09;、拦截器&#xff08;Interceptors&#xff09; 均属于请求处理流程的核心组件&#xff0c;它们共同构成了 NestJS 的…

Nastool+cpolar:群晖NAS用户的全场景影音自由方案

文章目录前言1. 本地搭建Nastool2. nastool基础设置3. 群晖NAS安装内网穿透工具4. 配置公网地址小结5. 配置固定公网地址**第二版&#xff1a;技术整合与效率提升导向****第二版&#xff1a;技术整合与效率提升导向****第二版&#xff1a;技术整合与效率提升导向**Nastool与cpo…

从零开始:Kaggle 竞赛实战入门指南

一、Kaggle社区概述 Kaggle 是全球最大的数据科学和机器学习社区&#xff0c;由Anthony Goldbloom于2010年创立&#xff0c;2017年被Google收购。平台专注于数据科学竞赛、开源数据集共享、协作编程以及技能学习&#xff0c;吸引了从初学者到专业数据科学家的广泛用户群体。 …

sqli-labs:Less-16关卡详细解析

1. 思路&#x1f680; 本关的SQL语句为&#xff1a; $uname".$uname."; $passwd".$passwd."; $sql"SELECT username, password FROM users WHERE username($uname) and password($passwd) LIMIT 0,1";注入类型&#xff1a;字符串型&#xff08;…

Lipschitz连续函数

Lipschitz function 一、说明 在数学分析中&#xff0c;Lipschitz连续性以德国 数学家 鲁道夫利普希茨 (Rudolf Lipschitz)的名字命名&#xff0c;是函数一致连续性的强形式。直观地说&#xff0c;Lipschitz连续函数的变化速度有限&#xff1a;存在一个实数&#xff0c;使得对于…

Dynamics 365 business central 与Shopify集成

Dynamics 365 Business Central&#xff08;简称 D365 BC&#xff09; 与 Shopify 的集成&#xff0c;能帮助企业实现前端电商平台&#xff08;Shopify&#xff09;与后端 ERP 系统&#xff08;Business Central&#xff09;之间的无缝数据同步&#xff0c;是一种典型的 ERP 与…

TCP RTO 与丢包检测

TCP RTO 是它 40 多年前唯一丢包检测策略&#xff0c;也是当前最后的丢包检测兜底策略&#xff0c;它几乎从没变过。 有个咨询挺有趣&#xff0c;以其案例为背景写篇随笔。大致意思是&#xff0c;嫌 TCP RTO 太大&#xff0c;游戏场景丢包卡顿怎么办&#xff1f;我提供了几行代…

安装php和配置环境变量

为了简单方便&#xff0c;先下载vscode然后下载对应的php安装包&#xff0c;然后配置环境变量&#xff0c;然后点击运行即可下载对应版本的php&#xff0c;这个版本凑合用然后下载完之后解压配置环境变量搜索环境变量将路径添加到环境变量中然后打开vscode添加变量具体看实际路…

Rabbit MQ的消息模式-Java原生代码

一.简单模式1.1.核心逻辑生产者 → 队列 → 单个消费者&#xff08;1:1 直连&#xff09;&#xff0c;消息被消费后自动从队列删除。1.2.关键特性无交换器&#xff08;其实使用的是默认交换机不是显示指定&#xff09;&#xff0c;直接指定队列 消息默认自动确认&#xff08;au…

【lucene】使用docvalues的案例

下面给出一段 可直接跑通 的 Lucene 8.5.0 示例代码&#xff0c;演示如何1. 建索引时为两个字段启用 DocValues&#xff08;一个 NumericDocValues&#xff0c;一个 SortedDocValues&#xff09;&#xff1b; 2. 用 IndexSearcher 按 DocValues 排序&#xff1b; 3. 用 Facet…

IntelliJ IDEA 配置 Maven 阿里云镜像加速源全流程

1. 为什么要加国内镜像源&#xff1f;国内网络访问 Maven 中央仓库经常超时、依赖下载极慢或失败。配置阿里云等国内镜像后&#xff0c;Java 项目依赖下载飞快&#xff0c;极大提升开发效率&#xff0c;是中国开发者必做优化&#xff01;2. 添加阿里云镜像源的步骤&#xff08;…

【worklist】worklist的hl7、dicom是什么关系

HL7和DICOM在Worklist系统中是互补的关系&#xff0c;它们各自承担不同的角色&#xff0c;但协同工作以实现完整的医疗信息系统集成。HL7与DICOM Worklist的关系1. 功能分工DICOM Worklist (Modality Worklist - MWL)主要用于影像设备获取患者和检查信息基于DICOM协议&#xff…

位运算-面试题01.01.判定字符是否唯一-力扣(LeetCode)

一、题目解析1、s[i]仅包含小写字母2、字符串的长度为[0&#xff0c;100]二、算法原理解法1&#xff1a;哈希表用哈希表记录s[i]的字符&#xff0c;如果有重复的&#xff0c;则返回false优化1&#xff1a;由于s[i]中只有小写字母&#xff0c;所以可以创建一个int hash[26]的数组…

wsl /lib/x86_64-linux-gnu/libc.so.6: version GLIBC_2.28‘ not found

遇到的问题并没有解决&#xff0c;这个 glibc-2.28 应该是安装好了 Ubuntu18 问题描述&#xff1a;Ubuntu18 WSL 无法启动 VS Code &#xff0c;因为node版本问题 rootUbuntu18:~# code . /lib/x86_64-linux-gnu/libc.so.6: version GLIBC_2.28 not found (required by /root…

Windows系统ffmpeg.dll丢失怎么办?从错误分析到永久修复的完整流程

您是否遇到过这样的情况&#xff1a;打开心爱的视频编辑软件时&#xff0c;系统突然提示无法启动此程序&#xff0c;因为计算机中丢失ffmpeg.dll&#xff1f;别担心&#xff0c;这个问题比您想象的要常见得多。作为专业的技术支持团队&#xff0c;我们已经帮助数千用户解决了类…

LaTeX 复杂图形绘制教程:从基础到进阶

系列文章目录 第一章&#xff1a;深入了解 LaTeX&#xff1a;科技文档排版的利器 第二章&#xff1a;LaTeX 下载安装保姆级教程 第三章&#xff1a;LaTeX 创建工程并生成完整文档指南 第四章&#xff1a;LaTeX 表格制作全面指南 文章目录系列文章目录前言一、​LaTeX 绘图工具…

用 Go Typed Client 快速上手 Elasticsearch —— 从建索引到聚合的完整实战

1. 准备工作 go get github.com/elastic/go-elasticsearch/v9小贴士 如果你的集群启用了安全特性&#xff0c;需要在 elasticsearch.Config 中配置 Username/Password 或 APIKey。Typed Client 通过 NewTypedClient 创建&#xff0c;内部复用 *http.Client&#xff0c;建议全局…