SpringBoot实战项目第一天
环境搭建
后端部分需要准备:
sql数据库
创建SpringBoot工程,引入对应的依赖(web\mybatis\mysql驱动)
配置文件application.yml中引入mybatis的配置信息
创建包结构,并准备实体类
完成今日开发后项目部分内容如下图示

用户注册于登录部分相关内容
注册
谈到注册,首先就要看看数据库中用户表的构成:

然后对应的,完成User实体类的开发
@Data
//lombok 在编译阶段,为实体类自动生成setter getter toString
// pom文件中引入依赖 在实体类上添加注解
public class User {private Integer id;//主键IDprivate String username;//用户名private String password;//密码private String nickname;//昵称private String email;//邮箱private String userPic;//用户头像地址private LocalDateTime createTime;//创建时间private LocalDateTime updateTime;//更新时间
}
此处用到了lombok技术,该技术可以在java文件编译时自动为变量生成getter、setter方法和tostring方法,后期实体类的开发也均会用到该技术。
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
接下来,就是要完成Mapper -> Service -> Controller这三层的对应开发。
在开发之前,我们要明确开发需求,即用户的注册。
而在用户注册时,会出现两种情况,注册成功与注册失败。此时我们粗略地将这两种情况对应为
数据库中没有该用户名对应行 -> 该用户还尚不存在 ->允许注册 ->注册
数据库中存在该用户名对应行 -> 该用户已经存在 -> 不允许注册 ->返回注册失败原因
理清逻辑后我们从Mapper层开始开发
首先,我们要注意到,在用户注册时我们会首先对数据库中是否已经存在该用户进行检测,如果没有,再在数据库中录入新用户信息
这就涉及到了sql中的两种操作,@select与@insert,所以,我们在Mapper层的接口中就要提供这两个操作
@Mapper
public interface UserMapper {@Select("select * from user where username = #{username}")User getByUserName(String username);@Insert("insert into user(username,password,create_time,update_time)"+"values (#{username},#{password},now(),now())")void add(String username, String password);
}
不要忘记使用@Mapper注册该类!
再来看Service层
service层开发较为简单,只需要将dao层的对应方法调用
service接口
public interface UserService {//用户名查询用户User getByUserName(String username);//新用户注册void register(String username, String password);
}
而impl文件中在实现这些方法之余,我们在service层会对用户输入的密码进行加密,这里使用到了MD5加密
@Service
public class SuerServiceImpl implements UserService {@AutowiredUserMapper userMapper;@Overridepublic User getByUserName(String username) {User u = userMapper.getByUserName(username);return u;}@Overridepublic void register(String username, String password) {//密码加密String p = Md5Util.getMD5String(password);userMapper.add(username,p);}
}
记得检查传入mapper层的密码,一定要是加密后的!
MD5:
public class Md5Util {/*** 默认的密码字符串组合,用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合*/protected static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};protected static MessageDigest messagedigest = null;static {try {messagedigest = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException nsaex) {System.err.println(Md5Util.class.getName() + "初始化失败,MessageDigest不支持MD5Util。");nsaex.printStackTrace();}}/*** 生成字符串的md5校验值** @param s* @return*/public static String getMD5String(String s) {return getMD5String(s.getBytes());}/*** 判断字符串的md5校验码是否与一个已知的md5码相匹配** @param password 要校验的字符串* @param md5PwdStr 已知的md5校验码* @return*/public static boolean checkPassword(String password, String md5PwdStr) {String s = getMD5String(password);return s.equals(md5PwdStr);}public static String getMD5String(byte[] bytes) {messagedigest.update(bytes);return bufferToHex(messagedigest.digest());}private static String bufferToHex(byte bytes[]) {return bufferToHex(bytes, 0, bytes.length);}private static String bufferToHex(byte bytes[], int m, int n) {StringBuffer stringbuffer = new StringBuffer(2 * n);int k = m + n;for (int l = m; l < k; l++) {appendHexPair(bytes[l], stringbuffer);}return stringbuffer.toString();}private static void appendHexPair(byte bt, StringBuffer stringbuffer) {char c0 = hexDigits[(bt & 0xf0) >> 4];// 取字节中高 4 位的数字转换, >>>// 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换stringbuffer.append(c0);stringbuffer.append(c1);}}
最后一步,我们进行Controller层的开发
在controller层中,我们需要进行相应的逻辑判断来验证该用户名是否已经被占用,具体操作如下:
@RestController
@RequestMapping("/user")
public class UserController {@AutowiredUserService userService;@PostMapping("/register")public Result register(String username,String password){//查询该用户名是否已经存在User u = userService.getByUserName(username);if (u==null){//用户名没有被占用,注册userService.register(username,password);return Result.success();} else {return Result.error("用户名被占用!");}}
}
Result实体类如下:
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Result<T> {private Integer code;//业务状态码 0-成功 1-失败private String message;//提示信息private T data;//响应数据//快速返回操作成功响应结果(带响应数据)public static <E> Result<E> success(E data) {return new Result<>(0, "操作成功", data);}//快速返回操作成功响应结果public static Result success() {return new Result(0, "操作成功", null);}public static Result error(String message) {return new Result(1, message, null);}
}
最后的最后,我们使用测试软件对注册部分进行测试
先看新用户注册正常,注册成功情况

数据库存储情况

可以看到密码的加密工作也顺利完成
再来看看注册失败的情况,这里我们直接使用刚才的账密注册

注册失败,至此,我们的注册功能已完成最基本的开发与测试。
当然,我们在日常生活中会发现,账户与密码会有一个基本的校验,即a-b位的非空字符,显然,我们还需要对账密进行进行长度检验。
账户密码长度参数校验
这里我预设的账户长度为4-16位
密码长度位11-16位
校验我们在controller层完成
@RestController
@RequestMapping("/user")
public class UserController {@AutowiredUserService userService;@PostMapping("/register")public Result register(String username,String password){if(username != null && username.length()>=4 && username.length() <= 16 &&password != null && password.length() >= 11 && password.length() <=16){//查询该用户名是否已经存在User u = userService.getByUserName(username);if (u==null){//用户名没有被占用,注册userService.register(username,password);return Result.success();} else {return Result.error("用户名被占用!");}}else{return Result.error("用户名或密码输入不合法!");}}
}
当然,我们会发现,仅仅校验账户与密码这两个参数就会导致我们的逻辑判断代码如此繁琐,Spring当然也为我们提供了简化方法——Spring Validation框架
Spring Validation框架 :Spring提供的一个参数校验框架,使用预定义的注解完成参数校验
Spring Validation框架使用流程
第一步、引入Spring Validation框架起步依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
第二步、在参数前面添加@Pattren注解
public Result register(@Pattern(regexp = "^\\S{4,16}$") String username, @Pattern(regexp = "^\\S{11,16}$")String password){
第三步、在Controller类上添加@Validated注解
@RestController
@RequestMapping("/user")
@Validated
public class UserController {@AutowiredUserService userService;@PostMapping("/register")public Result register(@Pattern(regexp = "^\\S{4,16}$") String username, @Pattern(regexp = "^\\S{11,16}$")String password){//查询该用户名是否已经存在User u = userService.getByUserName(username);if (u==null){//用户名没有被占用,注册userService.register(username,password);return Result.success();} else {return Result.error("用户名被占用!");}}
}
当我们输入不合法的账密时,我们会发现,这里的报错不如我们之前手动返回的,所以我们要对其进行参数校验失败异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public Result handleExxception(Exception e){e.printStackTrace();return Result.error(StringUtils.hasLength(e.getMessage())?e.getMessage():"操作失败,");}
}
再次使用非法账密测试

可以看到异常处理功能正常运行
登录
在开发之前,我们要明确开发需求,即用户的登录(成功登录后需求返回一个 jwt token 令牌)。
而在用户登录时,会出现三种情况,账密正确,成功登录、账号错误,登陆失败与密码错误,登陆失败。此时我们粗略地将这三种情况对应为
数据库中没有该用户名对应行 -> 该用户还尚不存在 ->登陆失败 ->返回登陆失败原因
数据库中存在该用户名对应行,但密码不对应 -> 密码输入错误 -> 登陆失败 -> 返回登录失败原因
数据库中存在该用户名对应行,且密码对应 -> 账户密码输入正确 -> 登陆成功
分析完需求,我们会发现我们在书写登录模块时需要对用户的帐户密码进行相应的逻辑判断,用到的sql语句为@select与@insert,这两个方法我们在注册模块已经完成了书写,所以我们直接在Controller层编写登录模块即可!
Controller层技术开发
@PostMapping("/login")public Result<String> login(@Pattern(regexp = "^\\S{4,16}$") String username, @Pattern(regexp = "^\\S{11,16}$")String password){//查询用户是否存在User lUser = userService.getByUserName(username);if(lUser == null){return Result.error("用户不存在!");}//查询密码是否正确(密码需要加密后再与数据库中密码比较)if (Md5Util.getMD5String(password).equals(lUser.getPassword())){return Result.success("jwt token 令牌");}return Result.error("密码错误!");}
可以看到,对于账密合法性判断我们采取了与注册时一样的操作, 逻辑判断部分也是简单的匹配,下面我们来对其进行测试
这是一组正确的账户密码测试,可以看到,此时我们暂时还没有编写jwt令牌的返回,暂时使用一个字符串代替

下面再进行一组错误账户名的测试

可以看到,错误信息如期。
最后在进行一组错误密码的测试

测试完毕,我们编辑的最最基础的登录部份功能正常运行!
登录认证
当我们需要将某些界面设置为登陆后可见时,我们就需要对其加入登录认证的功能,接下来就进行该功能的开发
我们先建立一个chesscontroller,供下例使用:
@RestController
@RequestMapping("/article")
public class ChessController {@PostMapping("/chess")public Result<String> chess(){return Result.success("读取所有的棋子数据!");}
}
登陆验证需要一个令牌,该令牌就是一段字符串,需要满足下列要求
承载业务数据,减少后续请求查询数据库次数
防篡改,保证信息的合法性和有效性
在web开发中最常用的令牌便是JWT令牌
JWT
全称:JSON Web Token
定义了一种简洁的、自包含的格式,用于通信双方以json数据格式安全的传输信息

组成:
第一部分:Header(头),记录令牌类型、签名算法等。例如:{"alg":"HS256","type":"JWT"}
第二部分:PayLoad(有效载荷),携带一些自定义信息、默认信息等。例如:{"id":"1","us"1"}
第三部分:Signature(签名),防止Token被篡改、切薄安全性。将header、payload加入指定密钥,通过指定签名算法计算而来
JWT-生成
首先导入对应依赖坐标
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version></dependency>
接下来编写对应的程序
public class JwtTest {@Testpublic void testGen(){Map<String, Object> claims = new HashMap<>();claims.put("id",1);claims.put("username","zmx");//生成jwt代码String token = JWT.create().withClaim("user",claims)//添加载荷.withExpiresAt(new Date(System.currentTimeMillis()+1000*60*12))//添加过期时间.sign(Algorithm.HMAC256("cacb"));//指定算法,配置密钥System.out.println(token);}
}
如上,我输入了一组简单的数据来测试
运行结果:
JWT-验证
@Testpublic void testParse(){//定义字符串,模拟用户传递的tokenString token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6InpteCJ9LCJleHAiOjE3MDY5NTUzNTN9.pZ0fYD5rRMPHXzAq_sLC6RKprPGwIiIHoimAuChTzdk";JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("cacb")).build();DecodedJWT decodedJWT = jwtVerifier.verify(token);//验证token,生成一个解析后的JWT对象Map<String, Claim> claims = decodedJWT.getClaims();System.out.println(claims.get("user"));}
使用上例生成的JWT进行验证
结果如下:

JWT校验时使用的签名密钥,必须和生成JWT令牌时使用的密钥是配套的
如果JWT令牌解析校验时报错,则说明JWT令牌被篡改或失效了,令牌非法
登录认证书写
由于JWT生成与验证的代码过于繁琐,所以我们选择使用一个工具类来承载JWT生成与验证的方法
public class JwtUtil {private static final String KEY = "cacb";//接收业务数据,生成token并返回public static String genToken(Map<String, Object> claims) {return JWT.create().withClaim("claims", claims).withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12)).sign(Algorithm.HMAC256(KEY));}//接收token,验证token,并返回业务数据public static Map<String, Object> parseToken(String token) {return JWT.require(Algorithm.HMAC256(KEY)).build().verify(token).getClaim("claims").asMap();}}
第一步、在登录界时生成token
@PostMapping("/login")public Result<String> login(@Pattern(regexp = "^\\S{4,16}$") String username, @Pattern(regexp = "^\\S{11,16}$")String password){//查询用户是否存在User lUser = userService.getByUserName(username);if(lUser == null){return Result.error("用户不存在!");}//查询密码是否正确(密码需要加密后再与数据库中密码比较)if (Md5Util.getMD5String(password).equals(lUser.getPassword())){Map<String,Object> claims = new HashMap<>();claims.put("id",lUser.getId());claims.put("usernname",lUser.getUsername());String token = JwtUtil.genToken(claims);return Result.success(token);}return Result.error("密码错误!");}
第二步、在需要验证token界面对应的接口验证token(复杂)
还是以list为例(token从请求头中的Authorization读取)
@GetMapping("/list")public Result<String> chess(@RequestHeader(name = "Authorization")String token , HttpServletResponse response){//验证tokentry {Map<String,Object> claims = JwtUtil.parseToken(token);return Result.success("读取所有的棋子数据!");} catch (Exception e){//设置HTTP响应状态码为401response.setStatus(401);return Result.error("请登录!");}}
测试结果如下:
验证token高效方法、使用拦截器统一验证token令牌
第一步、将验证token转移到拦截器中
@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//令牌验证String token = request.getHeader("Authorization");//验证tokentry {Map<String,Object> claims = JwtUtil.parseToken(token);//放行return true;} catch (Exception e){//设置HTTP响应状态码为401response.setStatus(401);//不放行return false;}}
}
第二步、书写配置类,注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册拦截器,登录接口和注册接口不拦截registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");}
}
注意:如例中的login与register接口不需要拦截,可以直接放行
第三步、修改简化被拦截的接口内容
@GetMapping("/list")public Result<String> chess(@RequestHeader(name = "Authorization") String token, HttpServletResponse response) {return Result.success("读取所有的棋子数据!");}
测试结果如下:
相关文章:
SpringBoot实战项目第一天
环境搭建 后端部分需要准备: sql数据库 创建SpringBoot工程,引入对应的依赖(web\mybatis\mysql驱动) 配置文件application.yml中引入mybatis的配置信息 创建包结构,并准备实体类 完成今日开发后项目部分内容如下图示 用户注册于登录部分…...
C# 信号量(Semaphore)详细使用案例
文章目录 简介信号量的工作原理使用场景使用示例其他使用实例1. 数据库连接池管理2. 文件读写同步3. 生产者消费者问题4. 打印任务队列同步5. Web服务器并发请求限制 简介 在C#中,信号量(Semaphore)是.NET框架提供的一个同步类,位…...
《Docker极简教程》--Docker基础--Docker的基本概念
在这篇文章中我们先大致的了解以下Docker的基本概念,在后续的文章中我们会详细的讲解这些概念以及使用。 一、容器(Container) 1.1 容器的定义和特点 容器的定义 容器是一种轻量级、可移植的软件打包技术,用于打包应用及其依赖项和运行环境,…...
【AIGC核心技术剖析】DreamCraft3D一种层次化的3D内容生成方法
DreamCraft3D是一种用于生成高保真、连贯3D对象的层次化3D内容生成方法。它利用2D参考图像引导几何塑造和纹理增强阶段,通过视角相关扩散模型执行得分蒸馏采样,解决了现有方法中存在的一致性问题。使用Bootstrapped Score Distillation来提高纹理&#x…...
新版MQL语言程序设计:外观模式的原理、应用及代码实现
文章目录 一、什么是外观模式二、外观模式的实现原理三、外观模式的应用范围四、外观模式应用实例银行系统的设计量化交易系统的设计 五、外观模式的代码实现 一、什么是外观模式 外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个…...
Docker 搭建mysql 集群(二)
PXC方案 很明显 PXC方案在任何一个节点写入的数据都会同步到其他节点,数据双向同步的(在任何节点上都可以同时读写) 创建MySQL PXC集群 1 安装PXC镜像 docker pull percona/percona-xtradb-cluster:5.7.21 2 为PXC镜像改名 docker tag pe…...
L1-018 大笨钟-java
输入样例1: 19:05输出样例1: DangDangDangDangDangDangDangDang输入样例2: 07:05输出样例2: Only 07:05. Too early to Dang. java import java.awt.desktop.SystemEventListener; import java.util.Scanner;public class M…...
monaco-editor布局篇(二)-自动换行
monaco-editor的换行方式,主要分为3种情况: 不换行按照编辑器宽度换行按照制定列数换行 主要受wordwrap和wordwrapcolumn控制,具体如下: 取值含义off不换行,会一直滚动on换行,文本将在视区宽度内自动换行…...
08-常用集合(容器)
上一篇: 07-使用Package、Crates、Modules管理项目 Rust 的标准库包含许多非常有用的数据结构,称为集合。大多数其他数据类型表示一个特定值,但集合可以包含多个值。与内置的数组和元组类型不同,这些集合指向的数据存储在堆上&…...
CentOS 中文乱码
CentOS 中文乱码 1、 查看自己系统有没有安装中文语言包,可使用 locale -a 命令列出所有可用的语言环境 如果有中文,则不用安装,如果没有,需要重新安装,使用 yum install kde-l10n-Chinese 2、 修改 i18n 和 locale…...
Java List中对象根据id去重,并处理重复对象的某个字段
List中对象根据id去重 一、需求二、解决 一、需求 参考文章:https://blog.csdn.net/A_Gui_Code/article/details/106978867 对在list集合中对象根据主键id去重,同时需要对重复对象的某个字段进行单独处理。 例如,对象包含字段如下, 当某个对象重复时&a…...
小周学JAVA—八股六
自动装箱和拆箱 Java中基础数据类型与它们对应的包装类见下表: 原始类型包装类型booleanBooleanbyteBytecharCharacterfloatFloatintIntegerlongLongshortShortdoubleDouble 装箱:将基础类型转化为包装类型。 拆箱:将包装类型转化为基础类…...
【深度学习】从0完整讲透深度学习第2篇:TensorFlow介绍和基本操作(代码文档已分享)
本系列文章md笔记(已分享)主要讨论深度学习相关知识。可以让大家熟练掌握机器学习基础,如分类、回归(含代码),熟练掌握numpy,pandas,sklearn等框架使用。在算法上,掌握神经网络的数学原理,手动实…...
题目: 有1234个数字, 组成多个互不相同且无重复数字的三位数? 都是多少?
lua脚本如下 最原始的解题方法 local str{} local i, j, k0, 0, 0 for i1, 4 do for j1, 4 do for k1, 4 do if i~j and i~k and j~k then str[#str1]i..j..k end end end end print("组成的数有"..#str) print(table.unpack(str)) 运行的结果如下 组成的数有24 1…...
由亚马逊云科技 Graviton4 驱动的全新内存优化型实例 Amazon EC2 实例(R8g),现已开放预览
下一代 Amazon Elastic Compute CloudAmazon EC2) 实例的预览版现已公开 提供。全新的 R8g 实例 搭载新式 Graviton4 处理器,其性价比远超任何现有的内存优化实例。对于要求较高的内存密集型工作负载,R8g 实例是不二之选:大数据分析、高性能数…...
sqlserver alwayson部署文档手册
1、ALWAYSON概述 详细介绍参照官网详细文档,我就不在这里赘述了: https://learn.microsoft.com/zh-cn/sql/database-engine/availability-groups/windows/overview-of-always-on-availability-groups-sql-server?viewsql-server-ver16 下图显示的是一个包含一个…...
【FFmpeg】ffplay 命令行参数 ① ( 设置播放分辨率 | 禁用 音频 / 视频 / 字幕 选项 )
文章目录 一、ffplay 命令行参数 - 设置播放分辨率1、强制设置通用播放分辨率 -x -y 参数2、命令行示例 - 正常播放视频3、命令行示例 - 强制设置播放分辨率4、设置 YUV 播放分辨率 -video_size 和 像素设置 -pixel_format5、全屏播放 -fs 参数 二、ffplay 命令行参数 - 禁用 音…...
CSS写渐变边框线条
box-sizing: border-box; border-top: 1px solid; border-image: linear-gradient(to right, red, blue) 1;...
【Linux网络编程三】Udp套接字编程网络应用场景
【Linux网络编程三】Udp套接字编程网络应用场景 应用场景一:远程命令执行应用场景二:与Windos端相互通信应用场景三:简单聊天1.多线程化2.输入输出分开 应用场景一:远程命令执行 简单的服务器上一篇已经完成,接下来我…...
计算机网络实验二
目录 实验二 交换机的基本配置 1、实验目的 2、实验设备 (1)实验内容: (2)练习: 1.实验内容一:(交换机的配置方式) 2.实验内容二:(交换机…...
TimesFM时间序列预测模型实战:从基础模型到高效部署的完整路径
TimesFM时间序列预测模型实战:从基础模型到高效部署的完整路径 【免费下载链接】timesfm TimesFM (Time Series Foundation Model) is a pretrained time-series foundation model developed by Google Research for time-series forecasting. 项目地址: https://…...
从安装到实战:在快马平台部署一个基于openclaw的新闻采集demo
今天想和大家分享一个完整的实战项目:在InsCode(快马)平台上从零开始部署一个基于openclaw的新闻采集demo。这个项目特别适合想快速验证爬虫框架能力的朋友,因为平台的一键部署功能让我们能跳过繁琐的环境配置,直接进入实战环节。 为什么选择…...
一码一物的生成软件,为什么总能先把窜货和返利黑洞堵住?
一码一物的生成软件,为什么总能先把窜货和返利黑洞堵住?很多老板嘴上说生意难做,真把账摊开看,难的不是卖不出去,而是货卖到哪儿不知道、钱花给谁不清楚、促销有没有真拉动更说不明白。一码一物的生成软件,…...
Shox96 Progmem:嵌入式Flash短字符串高效压缩方案
1. Shox96 Progmem 压缩库技术解析:面向嵌入式 Flash 的短字符串高效压缩方案1.1 工程背景与设计动因在资源受限的嵌入式系统中,Flash 存储空间始终是关键瓶颈。以典型 Cortex-M0/M3 MCU(如 STM32F072、nRF52832)为例,…...
抖音批量下载工具终极指南:免费下载去水印视频的完整教程
抖音批量下载工具终极指南:免费下载去水印视频的完整教程 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback su…...
2025届学术党必备的降重复率网站横评
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 研究人工智能开题报告的工具,借助自然语言处理技术,靠着学术大数据分…...
基于Matlab的路面裂缝检测识别系统:实现精准路面“体检”
基于Matlab的路面裂缝检测识别系统设计,载入待识别图片,对目标图像进行直方图均衡化、中值滤波去噪、对比度增强、二值化处理、二值化滤波、裂缝识别、裂缝判断、裂分拼接、裂缝投影及标记等一系列操作,完成路面识别的准确识别 程序已调通&am…...
Nunchaku FLUX.1-dev效果展示:4步生成惊艳图片案例分享
Nunchaku FLUX.1-dev效果展示:4步生成惊艳图片案例分享 你是否曾经被AI生成图片的漫长等待时间所困扰?传统文生图模型往往需要20步以上的推理才能获得理想效果,而今天我要展示的Nunchaku FLUX.1-dev模型,仅需4步就能生成令人惊艳…...
别再让AI瞎猜了!5个实战案例教你写出让Vibe Coding一次成功的提示词
别再让AI瞎猜了!5个实战案例教你写出让Vibe Coding一次成功的提示词 当你在Vibe Coding平台上输入一串提示词,满心期待地按下生成按钮,结果却得到一个与你想象中完全不同的产物——这种经历相信很多开发者都不陌生。为什么AI总是"误解&q…...
G-Helper:重塑华硕硬件控制体验的轻量级开源解决方案
G-Helper:重塑华硕硬件控制体验的轻量级开源解决方案 【免费下载链接】g-helper Lightweight, open-source control tool for ASUS laptops and ROG Ally. Manage performance modes, fans, GPU, battery, and RGB lighting across Zephyrus, Flow, TUF, Strix, Sca…...
