【智能协同云图库】智能协同云图库第八弹:基于阿里云百炼大模型—实现 AI 扩图功能

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


AI 扩图功能


需求分析


随着 AI 的高速发展,AI 几乎可以应用到任何传统业务中,增强应用的功能,带给用户更好的体验。

对于图库网站来说,AI 也有非常多的应用空间,比如可以利用 AI 绘图大模型来编辑图片,实现扩图、擦除补全、图配文、去水印等功能。

image-20250728001442679

以 AI 扩图功能为例,用户可以选择一张已上传的图片,通过 AI 编辑得到新的图片,并根据情况自行选择是否保存。

该功能不限制仅在空间内使用,公共图库也可以支持。


方案设计


1. AI 绘图大模型选择


AI绘图大模型我们自己是搞不来的,可以选择一个市面上支持AI绘图的大模型。

选择 AI 大模型时,我们最关注的应该是生成效果、生成速度还有价格了吧?当然,对我们学习来说,最关注的还是价格,毕竟绘画大模型的费用不低。

国内的 AI 绘图大模型比较推荐阿里云百炼,它是一站式的大模型开发及应用构建平台,可以通过简单的界面操作,在5分钟内开发出一款大模型应用,并在线体验效果。

image-20250728001824875


创建好应用后,利用官方提供的 API 或SDK,直接通过几行代码,就能在项目中使用大模型应用:

image-20250728001918755


通过阅读 官方文档,发现它是支持AI图像编辑与生成功能的,包括 AI 扩图,支持 HTTP 调用,符合我们的需求。

image-20250728001951264


在控制台也能看到对应的图像画面扩展模型:

image-20250728002039144


百炼的大模型提供了新人免费额度,可以通过文档或者点进大模型了解,对于学习用来说足够了:

image-20250728002304218


经过测试,图片生成效果、生成速度都是不错的,因此,本项目将选用阿里云百炼实现AI扩图功能。

image-20250728002330847


建议:之前没接触过类似 AI 大模型平台的同学,先多利用网页控制台熟悉 AI 大模型的 Prompt,了解不同大模型的区别。

推荐学习网站:WaytoAGI-通往AGI之路,最好的 AI 知识库和工具站


2. 调用方式


通过阅读 AI 图像扩展的官方文档,我们发现,API 只支持异步方式调用。

image-20250729114000515


这是因为 AI 绘画任务计算量大且耗时长,同步调用会导致服务器线程长时间被单个任务占用,限制了并发处理能力,增加了超时和系统崩溃的风险。

通过异步调用,服务器可以将任务放入队列中,合理调度资源,避免阻塞主线程,从而更高效地服务多个用户请求,提升整体系统的稳定性和可扩展性。

特点:客户端可以直接获取到结果,调用更方便。

image-20250728002700553


异步调用流程如下,客户端需要在提交任务后,不断轮询请求,来检查任务是否执行完成。

image-20250728002822635

由于 AI 接口已经选择了异步调用,所以我们作为要调用 AI 接口的客户端,要使用轮询的方式来检查任务状态是否为“已完成”,如果完成了,才可以获取到生成的图片。

那么是前端轮询还是后端轮询呢?


前端轮询

  • 流程:前端调用后端提交任务后得到任务 ID,然后通过定时器轮询请求查询任务状态接口,直到任务完成或失败。
  • 示例代码:
// 提交任务
async function submitTask() {const response = await fetch('/api/createTask', { method: 'POST' });const { taskId } = await response.json();checkTaskStatus(taskId);
}// 调用submitTask();// 检查任务状态
async function checkTaskStatus(taskId) {const intervalId = setInterval(async () => {const response = await fetch(`/api/taskStatus?taskId=${taskId}`);const { status, result } = await response.json();if (status === 'success') {console.log('Task completed:', result);clearInterval(intervalId); // 停止轮询} else if (status === 'failed') {console.error('Task failed');clearInterval(intervalId); // 停止轮询}}, 2000); // 每隔 2 秒轮询
}

后端轮询

  • 流程:后端通过循环或定时任务检测任务状态,接口保持阻塞,直到任务完成或失败,直接返回结果给前端。
  • 示例代码:
@RestController
public class TaskController {@PostMapping("/createTask")public String createTask() {String taskId = taskService.submitTask();return taskId;}@GetMapping("/waitForTask")public ResponseEntity<String> waitForTask(@RequestParam String taskId) {while (true) {String status = taskService.checkTaskStatus(taskId);if ("success".equals(status)) {return ResponseEntity.ok("Task completed");} else if ("failed".equals(status)) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Task failed");}try {Thread.sleep(2000); // 等待 2 秒后重试} catch (InterruptedException e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error occurred");}}}
}
  • 后端轮询问题:后端轮询容易因为任务阻塞导致资源耗尽。
  • 推荐方案:通常推荐前端轮询。除非有明确的需求要求时,才考虑后端轮询,比如任务结果需实时返回且对网络请求数敏感。(或者学习时不想写前端的同学哈哈)
  • 选择:此处我们也选择前端轮询方案实现。

💡 小贴士:从这个方案设计中,我们也能感受到,如果你同时了解前端和后端,可以结合二者设计出更合理的方案,而不是把所有的“重担”都交给前端或者后端一方。所以企业中开需求评审会或者讨论方案时,前后端需要紧密协作。


后端开发


1. AI 扩图 API


(1) 创建 API Key

首先开发业务依赖的基础能力,也就是 AI 扩图 API。

1. 需要先进入阿里云百炼控制台开通服务:

image-20250728003152739


2. 开通推理能力:

image-20250728003236041


3. 开通之后,我们要在控制台获取API Key,可参考文档:

image-20250729141002688

开通之后,在控制台获取 API Key,可参考文档。

能够在控制台查看到 API Key,注意,API Key 一定不要对外泄露!


接下来,我们需要根据下面的请求头使用 Java 来构造扩图请求实体类数据模型

image-20250729142258249


通过阅读文档发现,百炼支持通过 SDK 或 HTTP 调用。

虽然官方写的支持 Java SDK,但 AI 扩图功能中对 SDK 的介绍非常少,此处考虑到兼容性,我们还是使用 HTTP 调用。

image-20250728003431752


4. 由于使用异步的方式,需要开发创建任务和查询结果 2 个 API。

image-20250728003448202


5. 填写配置文件:在配置文件中填写获取到的 apiKey

image-20250729141541522

# 阿里云 AI 配置
aliYunAi:apiKey: xxxx

(2) 创建请求参数接收类

api 包下新建 aliyunai 包,存放阿里云 AI 相关代码。

image-20250729141819566


aliyunai.model 包下新建数据模型类,可以让 AI 根据官方文档中的请求响应信息,自动生成请求实体类,无需自己手动编写。

复制下面的请求体内容,交给 AI 生成:

image-20250729142511438


code is cheap, show me the talk !

image-20250729142914990


由于每个 AI 图片处理操作的请求响应都有一些区别,所以单独给 AI 扩图功能编写具体的请求响应类。创建扩图任务请求类:

@Data
public class CreateOutPaintingTaskRequest implements Serializable {/*** 模型,例如 "image-out-painting"*/private String model = "image-out-painting";/*** 输入图像信息*/private Input input;/*** 图像处理参数*/private Parameters parameters;@Datapublic static class Input {/*** 必选,图像 URL*/@Alias("image_url")private String imageUrl;}@Datapublic static class Parameters implements Serializable {/*** 可选,逆时针旋转角度,默认值 0,取值范围 [0, 359]*/private Integer angle;/*** 可选,输出图像的宽高比,默认空字符串,不设置宽高比* 可选值:["", "1:1", "3:4", "4:3", "9:16", "16:9"]*/@Alias("output_ratio")private String outputRatio;/*** 可选,图像居中,在水平方向上按比例扩展,默认值 1.0,范围 [1.0, 3.0]*/@Alias("x_scale")@JsonProperty("xScale")private Float xScale;/*** 可选,图像居中,在垂直方向上按比例扩展,默认值 1.0,范围 [1.0, 3.0]*/@Alias("y_scale")@JsonProperty("yScale")private Float yScale;/*** 可选,在图像上方添加像素,默认值 0*/@Alias("top_offset")private Integer topOffset;/*** 可选,在图像下方添加像素,默认值 0*/@Alias("bottom_offset")private Integer bottomOffset;/*** 可选,在图像左侧添加像素,默认值 0*/@Alias("left_offset")private Integer leftOffset;/*** 可选,在图像右侧添加像素,默认值 0*/@Alias("right_offset")private Integer rightOffset;/*** 可选,开启图像最佳质量模式,默认值 false* 若为 true,耗时会成倍增加*/@Alias("best_quality")private Boolean bestQuality;/*** 可选,限制模型生成的图像文件大小,默认值 true* - 单边长度 <= 10000:输出图像文件大小限制为 5MB 以下* - 单边长度 > 10000:输出图像文件大小限制为 10MB 以下*/@Alias("limit_image_size")private Boolean limitImageSize;/*** 可选,添加 "Generated by AI" 水印,默认值 true*/@Alias("add_watermark")private Boolean addWatermark = false;}
}

image-20250729144432756

注意:上述代码中,某些字段打上了 Hutool 工具类的 @Alias 注解。这个注解仅对 Hutool 的 JSON 转换生效,对 SpringMVC 的 JSON 转换没有任何影响。

  • 这里有一个很坑的地方,经过测试发现,前端如果传递参数名 xScale,是无法赋值给 xScale 字段的;但是传递参数名 xscale,就可以赋值。

  • 这是因为 SpringMVC 对于第二个字母是大写的参数无法映射(和参数类别无关)。参考博客


解决方案:给这些字段增加 @JsonProperty 注解。

/*** 可选,图像居中,在水平方向上按比例扩展,默认值 1.0,范围 [1.0, 3.0]*/
@Alias("x_scale")
@JsonProperty("xScale")
private Float xScale;/*** 可选,图像居中,在垂直方向上按比例扩展,默认值 1.0,范围 [1.0, 3.0]*/
@Alias("y_scale")
@JsonProperty("yScale")
private Float yScale;

为什么 SpringMVC 要这样设计,通过查阅了解到,这是因为 Jackson 在处理字段名与 JSON 属性名映射时,会依赖 Java 的标准命名规范反射 API

  • 举个例子,根据 JavaBean 的规范,属性名称与其访问器方法(getter 和 setter)之间的映射规则是:如果属性名以小写字母开头,第二个字母是大写(如 eMail),规范仍认为属性名称是 eMail,而访问器方法应为 geteMail()seteMail()
  • 但 Jackson 会尝试推断属性名为 email(因为 eMail 不常见),从而导致 JSON 中 eMailemail 可能无法正确映射。

记住结论即可:SpringMVC 默认的序列化器 Jackson 在字段名的第二个字母为大写时,无法正确映射;需要使用 @JsonProperty("yScale") 这样的注解正确映射


(3) 创建扩图任务响应类

image-20250729150247373

这个类同理,不要自己写,直接使用 AI 生成:

image-20250729145538788

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CreateOutPaintingTaskResponse {private Output output;/*** 表示任务的输出信息*/@Datapublic static class Output {/*** 任务 ID*/private String taskId;/*** 任务状态* <ul>*     <li>PENDING:排队中</li>*     <li>RUNNING:处理中</li>*     <li>SUSPENDED:挂起</li>*     <li>SUCCEEDED:执行成功</li>*     <li>FAILED:执行失败</li>*     <li>UNKNOWN:任务不存在或状态未知</li>* </ul>*/private String taskStatus;}/*** 接口错误码。* <p>接口成功请求不会返回该参数。</p>*/private String code;/*** 接口错误信息。* <p>接口成功请求不会返回该参数。</p>*/private String message;/*** 请求唯一标识。* <p>可用于请求明细溯源和问题排查。</p>*/private String requestId;
}

(4) 查询任务响应类

image-20250729150151780


根据官方文档响应的说明,使用 AI 生成对应的查询任务响应类

image-20250729150327051

@Data
@NoArgsConstructor
@AllArgsConstructor
public class GetOutPaintingTaskResponse {/*** 请求唯一标识*/private String requestId;/*** 输出信息*/private Output output;/*** 表示任务的输出信息*/@Datapublic static class Output {/*** 任务 ID*/private String taskId;/*** 任务状态* <ul>*     <li>PENDING:排队中</li>*     <li>RUNNING:处理中</li>*     <li>SUSPENDED:挂起</li>*     <li>SUCCEEDED:执行成功</li>*     <li>FAILED:执行失败</li>*     <li>UNKNOWN:任务不存在或状态未知</li>* </ul>*/private String taskStatus;/*** 提交时间* 格式:YYYY-MM-DD HH:mm:ss.SSS*/private String submitTime;/*** 调度时间* 格式:YYYY-MM-DD HH:mm:ss.SSS*/private String scheduledTime;/*** 结束时间* 格式:YYYY-MM-DD HH:mm:ss.SSS*/private String endTime;/*** 输出图像的 URL*/private String outputImageUrl;/*** 接口错误码* <p>接口成功请求不会返回该参数</p>*/private String code;/*** 接口错误信息* <p>接口成功请求不会返回该参数</p>*/private String message;/*** 任务指标信息*/private TaskMetrics taskMetrics;}/*** 表示任务的统计信息*/@Datapublic static class TaskMetrics {/*** 总任务数*/private Integer total;/*** 成功任务数*/private Integer succeeded;/*** 失败任务数*/private Integer failed;}
}

(5) 大模型调用API 开发

开发 API 调用类,通过 Hutool 的 HTTP 请求工具类来调用阿里云百炼的 API。

image-20250729151912615


注解3:创建任务的请求地址,在官方文档中可以找到

image-20250729152744229


注解4:查询任务状态的请求地址,在官方文档中同样可以找到

image-20250729152657100


注解6:根据官方文档填写请求头

image-20250729161231652


注解7:

image-20250729155943777


注解 11:填写查询任务需要发送的请求头

image-20250729161502430


@Slf4j
@Component  // 1. 这个类需要读取配置文件中的 APIKey
public class AliYunAiApi {// 2. 使用 @Value 注解 (必须是 Spring 包), 读取需要的配置文件@Value("${aliYunAi.apiKey}")private String apiKey;// 3. 创建任务地址public static final String CREATE_OUT_PAINTING_TASK_URL = "https://dashscope.aliyuncs.com/api/v1/services/aigc/image2image/out-painting";// 4. 查询任务状态  %s 用于替换实际任务的 {task_id}public static final String GET_OUT_PAINTING_TASK_URL = "https://dashscope.aliyuncs.com/api/v1/tasks/%s";// 5. 创建任务public CreateOutPaintingTaskResponse createOutPaintingTask(CreateOutPaintingTaskRequest createOutPaintingTaskRequest){if(createOutPaintingTaskRequest == null){throw new BusinessException(ErrorCode.OPERATION_ERROR, "扩图参数为空");}//        curl --location --request POST 'https://dashscope.aliyuncs.com/api/v1/services/aigc/image2image/out-painting' \
//        --header "Authorization: Bearer $DASHSCOPE_API_KEY" \
//        --header 'X-DashScope-Async: enable' \
//        --header 'Content-Type: application/json' \
//        --data '{
//        "model": "image-out-painting",
//                "input": {
//            "image_url": "http://xxx/image.jpg"
//        },
//        "parameters":{
//            "angle": 45,
//                    "x_scale":1.5,
//                    "y_scale":1.5
//        }
//    }'// 6. 复制上述请求, 然后构造 HTTP 请求, 可以用 AI 生成HttpRequest httpRequest = HttpRequest.post(CREATE_OUT_PAINTING_TASK_URL)  // 注解 3 的创建请求地址.header("Authorization", "Bearer" + apiKey)  // 填充自定义 APIKey.header("X-DashScope-Async", "enable") // 让用户必需显示开启异步, 也方便后续扩展.header("Content-Type", "application/json").body(JSONUtil.toJsonStr(createOutPaintingTaskRequest));// 使用 Hutool 的 JSONUtil, 因为刚刚的请求使用了 @Alias// 7. 使用 try...with 方法释放 httpRequest 的资源, 自动释放资源的对象必须实现 AutoCloseable 接口try(HttpResponse httpResponse = httpRequest.execute()){// 8. 响应码异常if(!httpResponse.isOk()){log.error("请求异常: {}", httpResponse.body());throw new BusinessException(ErrorCode.OPERATION_ERROR, "AI 扩图失败");}// 9. 将正常的响应体转为 JSON 格式的创建请求的响应对象CreateOutPaintingTaskResponse createOutPaintingTaskResponse = JSONUtil.toBean(httpResponse.body(), CreateOutPaintingTaskResponse.class);// 10. 拿到响应对象后, 根据响应对象 code 是否有值, 进一步判断扩图是否成功if (createOutPaintingTaskResponse.getCode() != null){String errMessage = createOutPaintingTaskResponse.getMessage();log.error("请求异常: {}", errMessage);throw new BusinessException(ErrorCode.OPERATION_ERROR, "AI 扩图失败" + errMessage);}return createOutPaintingTaskResponse;}}/*** 查询创建的任务** @param taskId 任务 ID* @return 查询任务响应*/public GetOutPaintingTaskResponse getOutPaintingTask(String taskId){if(StrUtil.isBlank(taskId)){throw new BusinessException(ErrorCode.PARAMS_ERROR, "任务 ID 不能为空");}// 11. 填写请求头, 发送请求
//        --header "Authorization: Bearer $DASHSCOPE_API_KEY" \
//        https://dashscope.aliyuncs.com/api/v1/tasks/86ecf553-d340-4e21-xxxxxxxxxString url = String.format(GET_OUT_PAINTING_TASK_URL , taskId); // 注解 4 查询请求的 URL , "%s" 替换为 taskIdtry(HttpResponse httpResponse = HttpRequest.get(url).header("Authorization", "Bearer" + apiKey) .execute()){// 响应码异常if(!httpResponse.isOk()){log.error("请求异常: {}", httpResponse.body());throw new BusinessException(ErrorCode.OPERATION_ERROR, "获取任务结果失败");}return JSONUtil.toBean(httpResponse.body(), GetOutPaintingTaskResponse.class);}}
}

注意:要按照官方文档的要求给请求头增加鉴权信息,拼接配置中写好的 apiKey

image-20250729233240094


2. 开发扩图 API 调用接口


(1) 数据模型开发

model.dto.picture 包下新建 AI 扩图请求类,用于接受前端传来的参数并传递给 Service 服务层。

image-20250729170415374


字段包括图片 id 和扩图参数:

@Data
public class CreatePictureOutPaintingTaskRequest implements Serializable {/*** 图片 id*/private Long pictureId;/*** 扩图参数*/private CreateOutPaintingTaskRequest.Parameters parameters;private static final long serialVersionUID = 1L;
}

我们只需要传一个已有的图片,即可实现扩图功能,具体流程:

  1. 前端构造 Parameters(内部类) 的各个参数,并与图片 ID 一起构造扩图请求;
  2. 前端向后端发送扩图请求
  3. 后端从请求中解析图片 ID图像处理参数 Parameters
  4. 查询数据库,找到图片 ID 对应的图片,并进行关于图片与空间的鉴权
  5. 图片的 URLParameters 作为参数,构造API 扩图请求,调用扩图 API;
  6. 扩图 API 解析请求,校验参数,创建扩图任务;
  7. 创建的扩图任务,放入大模型扩图任务队列中,并生成对应的 taskId 返回;
  8. 可以通过调用查看进度 API ,查看对应 taskId 对应的生成进度
  9. 扩图成功后,查看进度 API 会封装URL 到响应中,返回给前端;

(2) 扩图服务开发

在图片服务中编写创建扩图任务方法,从数据库中获取图片信息和 URL 地址,构造请求参数后调用 API 创建扩图任务

注意,如果图片有空间 id,则需要校验权限,直接复用以前的权限校验方法。

在这里插入图片描述

@Override
public void checkPictureAuth(User loginUser, Picture picture) {Long spaceId = picture.getSpaceId();Long loginUserId = loginUser.getId();if (spaceId == null) {// 公共图库, 仅本人和管理员可操作if (!picture.getUserId().equals(loginUserId) && !userService.isAdmin(loginUser)) {throw new BusinessException(ErrorCode.NO_AUTH_ERROR);}} else {// 私有空间, 仅空间管理员可操作if (!picture.getUserId().equals(loginUserId)) {throw new BusinessException(ErrorCode.NO_AUTH_ERROR);}}
}

在调用大模型接口前,先调用该方法,对图片进行鉴权,只有空间管理员,可以对图片调用扩图 API


接下来,我们对调用大模型 API 进行服务开发:

image-20250729171157489


/*** 创建扩图任务* @param createPictureOutPaintingTaskRequest  扩图请求* @param loginUser* @return*/
CreateOutPaintingTaskResponse createPictureOutPaintingTask(CreatePictureOutPaintingTaskRequest createPictureOutPaintingTaskRequest, User loginUser);

@Resource
private AliYunAiApi aliYunAiApi;@Override
public CreateOutPaintingTaskResponse createPictureOutPaintingTask(CreatePictureOutPaintingTaskRequest createPictureOutPaintingTaskRequest, User loginUser) {// 1. 根据请求获取图片 IDLong pictureId = createPictureOutPaintingTaskRequest.getPictureId();// 2. 查询数据库, 获取图片, 如果数据库没有该图片, 抛异常
//        Picture picture = this.getById(pictureId);
//        ThrowUtils.throwIf(picture == null, ErrorCode.NOT_FOUND_ERROR, "图片不存在");Picture picture = Optional.ofNullable(this.getById(pictureId)).orElseThrow(() -> new BusinessException(ErrorCode.NOT_FOUND_ERROR, "图片不存在"));// Optional.ofNullable(...): 安全地包装可能为 null 的查询结果;// orElseThrow(...):如果结果确实为 null, 就立即抛出指定的异常;// 3. 校验权限checkPictureAuth(loginUser, picture);// 4. 创建扩图任务请求CreateOutPaintingTaskRequest createOutPaintingTaskRequest = new CreateOutPaintingTaskRequest();CreateOutPaintingTaskRequest.Input input = new CreateOutPaintingTaskRequest.Input();// 内部类 Input, 也作为参数input.setImageUrl(picture.getUrl());createOutPaintingTaskRequest.setInput(input);createOutPaintingTaskRequest.setParameters(createPictureOutPaintingTaskRequest.getParameters());// 5. 调用 API 创建任务return aliYunAiApi.createOutPaintingTask(createOutPaintingTaskRequest);
}

(3) 扩图接口开发

PictureController 添加 AI 扩图接口,包括创建任务和查询任务状态接口:

image-20250729180034566

/*** 创建 AI 扩图任务*/
@PostMapping("/out_painting/create_task")
public BaseResponse<CreateOutPaintingTaskResponse> createPictureOutPaintingTask(@RequestBody CreatePictureOutPaintingTaskRequest createPictureOutPaintingTaskRequest,HttpServletRequest request) {if (createPictureOutPaintingTaskRequest == null || createPictureOutPaintingTaskRequest.getPictureId() == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR);}User loginUser = userService.getLoginUser(request);CreateOutPaintingTaskResponse response = pictureService.createPictureOutPaintingTask(createPictureOutPaintingTaskRequest, loginUser);return ResultUtils.success(response);
}

@Resource
private AliYunAiApi aliYunAiApi;/*** 查询 AI 扩图任务*/
@GetMapping("/out_painting/get_task")
public BaseResponse<GetOutPaintingTaskResponse> getPictureOutPaintingTask(String taskId) {ThrowUtils.throwIf(StrUtil.isBlank(taskId), ErrorCode.PARAMS_ERROR);GetOutPaintingTaskResponse task = aliYunAiApi.getOutPaintingTask(taskId);return ResultUtils.success(task);
}

(4) 接口测试

测试图片:

image-20250729234703974


发送扩图任务请求:

image-20250729234205880


响应:

image-20250729234244438


复制 taskId,调用查看任务接口:

image-20250729234337208


打开 outputImageUrl

image-20250729234445536


效果对比:

image-20250729234904886

至此,我们的 AI 图片编辑后端开发完成啦~~~~


在这里插入图片描述

在这里插入图片描述

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

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

相关文章

2025年Solar应急响应公益月赛-7月笔记ing

应急响应身为颜狗的我是真心觉得lovelymem的ui写得~~~~【任务1】应急大师题目描述&#xff1a;请提交隐藏用户的名称&#xff1f;print打印注册表&#xff0c;或者开启环境是就有【任务4】应急大师题目描述&#xff1a;请提交黑客创建隐藏用户的TargetSid&#xff08;目标账户安…

C++/CLI vs 标准 C++ vs C# 语法对照手册

&#x1f680; C/CLI vs 标准 C vs C# 语法对照手册&#x1f9e9; 核心类型系统对比 // 类型声明语法对比 标准 C C/CLI C# ─────────────────────────────────────────────────…

仓库管理系统-2-后端之基于继承基类的方式实现增删改查

文章目录 1 数据库表user 2 后端通用框架 2.1 User.java(实体类) 2.2 使用封装的方法(继承基类) 2.2.1 UserMapper.java(mapper接口) 2.2.2 UserService.java(service接口) 2.2.3 UserServiceImpl.java(service实现类) 2.2.4 UserController.java(控制器) 3 增删改查(封装的方法…

【el-table滚动事件】el-table表格滚动时,获取可视窗口内的行数据

一个简单的获取内容的办法 表格部分&#xff0c;主要是ref写一下<el-table :data"tableData" ref"tableRef"> </el-table>进入页面的时候绑定监听 mounted(){ // 绑定滚动事件this.$nextTick(() > {const table this.$refs.tableRef;const…

OCR 赋能自动阅卷:让评分更高效精准

考试阅卷中&#xff0c;OCR 技术正成为高效助手&#xff0c;尤其在客观题和标准化答题场景中表现亮眼。将考生答题卡扫描后&#xff0c;OCR 能快速识别填涂的选项、手写数字或特定符号&#xff0c;与标准答案比对后自动判分。相比人工阅卷&#xff0c;它能在短时间内完成成百上…

在docker中安装frp实现内网穿透

服务端frps 1.首先在服务器端安装frps docker pull snowdreamtech/frps2.本地创建frps的配置文件frps.ini [common] bind_port 7000 # frp 服务端控制端口 token xxxxx # 客户端认证密钥3.启动frps docker run -d --name frps \ --network host \ --restartalwa…

电脑开机后网络连接慢?

在数字化日益普及的今天&#xff0c;电脑已成为我们工作和生活中不可或缺的工具。但是&#xff0c;可能很多用户都遇到过电脑开机后网络连接慢的情况&#xff0c;这不仅影响了我们的工作效率&#xff0c;还极大降低了上网体验。怎么解决该问题呢&#xff1f;本文分享的这5个方法…

一分钟部署一个导航网站

先看效果1.部署教程 mkdir -p /home/ascendking/mysite cd /home/ascendking/mysite# 安装 WebStack-Hugo 主题git clone https://gitee.com/WangZhe168_admin/WebStack-Hugo.git themes/WebStack-Hugo# 将 exampleSite 目录下的文件复制到 hugo 站点根目录 cd /home/ascendki…

Rust实现微积分与高等数学公式

基于Rust实现高等数学中微积分 以下是基于Rust实现高等数学中微积分相关公式的示例整理,涵盖微分、积分、级数等常见计算场景。内容分为基础公式和进阶应用两类,提供可直接运行的Rust代码片段(需依赖num或nalgebra等库)。 微分运算 导数的数值近似(前向差分) 适用于函…

Android 键盘

基础知识1. 物理键盘&#xff08;Physical Keyboard&#xff09;定义物理键盘指的是设备上真实存在的、可以按压的键盘。例如&#xff1a;早期的 Android 手机&#xff08;如黑莓、摩托罗拉 Milestone&#xff09;自带的 QWERTY 键盘外接的蓝牙/USB 键盘平板或 Chromebook 上的…

SuperClaude Framework 使用指南

SuperClaude Framework 使用指南SuperClaude Framework 是一个开源配置框架&#xff0c;将 Claude Code 从通用 AI 助手转变为专业的上下文感知开发伙伴。该框架通过模板驱动架构应用软件工程原理&#xff0c;为专业软件开发工作流程提供了强大的增强功能。目前该项目处于 v3.0…

Ruby 发送邮件 - SMTP

Ruby 发送邮件 - SMTP 在互联网的世界中,邮件服务已经成为我们日常生活中不可或缺的一部分。而在开发过程中,使用Ruby发送邮件是一项基本技能。SMTP(Simple Mail Transfer Protocol)是互联网上用于发送电子邮件的标准协议。本文将详细介绍如何在Ruby中使用SMTP发送邮件。 …

Docker运行Ollama

1.docker-compose启动ollama 按照 ollama docker-compose配置说明 配置并启动ollama容器&#xff0c;启动成功后&#xff0c;浏览器访问 http://localhost:11434 如果显示如下即代表成功 如果你的服务器支持GPU&#xff0c;可添加GPU参数支持&#xff0c;参考&#xff1a;htt…

轻松管理 WebSocket 连接!easy-websocket-client

在前端开发中&#xff0c;WebSocket 是实现实时通信的核心技术&#xff0c;但原生 WebSocket 的连接管理&#xff08;如断连重连、心跳维护、事件监听&#xff09;往往需要编写大量重复代码。今天给大家分享一个好用的 WebSocket 连接管理库 —— easy-websocket-client&#x…

人工智能赋能社会治理:深度解析与未来展望

一、核心应用场景与技术实现1. 公共安全&#xff1a;智能防控与风险预警技术应用&#xff1a;立体化治安防控&#xff1a;AI摄像头集成人脸识别、行为分析、多目标追踪技术&#xff0c;提升破案率与公共安全能力。例如&#xff0c;深圳某区通过AI系统使盗窃案件破案率提升40%。…

解决使用vscode连接服务器出现“正在下载 VS Code 服务器...”

# 解决使用vscode连接服务器出现“正在下载 VS Code 服务器...”## 首先在vscode的输出中获取 commit idtext [17:17:41.679] Using commit id "c306e94f98122556ca081f527b466015e1bc37b0" and quality "stable" for server 从上面的体制中可以看出&#…

React 项目中使用 Redux 实现公共状态共享

在 React 项目中使用 Redux 实现公共下拉选状态共享并通知各组件更新的完整方案如下&#xff1a;1. 安装 Redux 必要依赖 npm install reduxjs/toolkit react-redux2. 创建 Redux Store 和 Slice store/selectSlice.js import { createSlice } from reduxjs/toolkit;const init…

彻底清理ArcGIS 10.2残留的步骤

文章目录前言一、彻底清理ArcGIS 10.2残留的步骤总结前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、彻底清理ArcGIS 10.2残留的步骤 &#x1f527; 彻底清理ArcGIS 10.2残留的…

JDK主流版本及推荐版本

根据当前Java生态发展&#xff08;截至2025年7月&#xff09;&#xff0c;结合主流企业实践、技术特性和支持周期&#xff0c;以下是JDK主流版本及推荐版本的详细分析&#xff1a;&#x1f9e9; 一、主流JDK版本现状​​JDK 8 (LTS)​​​​使用比例​​&#xff1a;约30-35%&a…

如何从 Web2 转型到 Web3

如何从 Web2 转型到 Web3如何从 Web2 转型到 Web3引言Web2 与 Web3 的核心差异转型的实用步骤1. 打基础&#xff1a;学区块链和 Web3 概念2. 学核心技术栈&#xff1a;从 Solidity 到 dApp3. 重新设计产品&#xff1a;混合模式起步4. 应对坑&#xff1a;技术、监管和安全5. 建社…