Java [后端] 开发日常记录(1)
目录
1、常用的注解
2、对字符串的处理
3、对JSON串的处理
-- The End --
详细如下:
1、常用的注解
- 若返回的字段中有NUll,则不返回
- @JsonInclude(value = JsonInclude.Include.NON_NULL)
//在实体类中添加这个注解
@JsonInclude(JsonInclude.Include.NON_NULL)
- @RequestBody
常用来接收处理application/json
、application/xml
等类型的数据 contentType 为 application/json类型
@RestController = @Controller + @ResponseBody
- @requestParam
@requestParam主要用于在SpringMVC后台控制层获取参数,类似一种是request.getParameter("name"),
它有三个常用参数:defaultValue = "0", required = false, value = "isApp";defaultValue 表示设置默认值,required 通过boolean设置是否是必须要传入的参数,value 值表示接受的传入的参数类型。
- @Synchronized
@synchronized 可以解决接口简单的并发,使用的时候只需要放在对应并发的接口或者代码块前面即可。 @synchronized 所处理的问题与锁(递归锁NSRecursiveLock)类似;可以防止不同的线程同时执行同一段代码。@synchronized 用着更方便,可读性更高, 自然效率会比较低。
递归锁: 同一个线程可以重复的加锁而不会导致死锁(互斥锁: 同一个线程重复加锁会导致死锁) ,加的递归锁全部执行完后 才会把资源让给别的线程。
@synchronized 递归锁详解_想名真难的博客-CSDN博客_递归锁原理
锁主要存在四种状态,依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁。但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级。
- @JsonFormat()
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")可以格式化时间,接口可以返回格式化后的时间。如:@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
推荐使用:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
- 后端数据校验(当然前端校验可能会更方便一些,可以前端校验的话,可以使用前端校验)
Validator + BindResult进行数据校验
Validator可以非常方便的制定校验规则,在实体类里需要校验的字段加上注解,每个注解对应不同的校验规则。
如:在实体类中的name添加
@ NotNull(message = "用户名不能为空")
@ Size(min = 6, max = 11, message = "用户名长度必须是6-16个字符")
private String username;
然后在接口中添加 注解@Valid
/*** 用户新增*/
@PostMapping("/add")
public String addUser(@RequestBody @Valid UserInfo userInfo, BindingResult bindingResult) {// 如果有参数校验失败,会将错误信息封装成对象组装在BindingResult里for (ObjectError error : bindingResult.getAllErrors()) {return error.getDefaultMessage();}return userInfoService.insertUserInfo(userInfo);
}//当然也可以这样,就会直接把异常返给前端了
@PostMapping("/add")
public String addUser(@RequestBody @Valid UserInfo userInfo) {return userInfoService.insertUserInfo(userInfo);}
校验的结果就会返回到BindingResult中,有错误信息就直接返回给前端了。
当然前端校验也可能会方便一些,前端vue中数据校验如下,在form中添加:rules="rules",然后在中定义即可:
: rules = "rules"// 表单校验data() {return {rules: {phone: [{required: true,message: "联系电话不能为空",trigger: "blur"}, {pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,message: "请输入正确的手机号码",trigger: "blur"}],}}
@PathVariable
@PathVariable 映射 URL 绑定的占位符;带占位符的 URL 是 Spring3.0 新增的,通过 URL 中的 {xxxx} 占位符可以通过@PathVariable(“xxxx“) 绑定到操作方法的入参中。
具体实例如下:
@PostMapping("/login/{name}/{pwd}")@ResponseBodypublic String loginTest(@PathVariable("name")String name, @PathVariable("pwd")String pwd){System.out.println("name = " + name);System.out.println("pwd = " + pwd);return "Success";}@DeleteMapping("/del/{ids}")public AjaxResult remove(@PathVariable Long[] ids) {System.out.println("ids = " + ids);return toAjax(deleteDataService.deleteDatainfoByIds(ids));}
@RequestHeader
获取发送请求地址的头部信息如:一些浏览器信息
Accept 浏览器可接受的MIME类型
Accept-Charset 浏览器支持的字符编码
Accept-Encoding 浏览器知道如何解码的数据编码类型(如 gzip)。Servlets 可以预先检查浏览器是否支持gzip并可以对支持gzip的浏览器返回gzipped的HTML页面,并设置Content-Encoding回应头(response header)来指出发送的内容是已经gzipped的。在大多数情况下,这样做可以加快网页下载的速度。
Accept-Language 浏览器指定的语言,当Server支持多语种时起作用。
Authorization 认证信息,一般是对服务器发出的WWW-Authenticate头的回应。
Connection 是否使用持续连接。如果servlet发现这个字段的值是Keep-Alive,或者由发出请求的命令行发现浏览器支持 HTTP 1.1 (持续连接是它的默认选项),使用持续连接可以使保护很多小文件的页面的下载时间减少。
Content-Length (使用POST方法提交时,传递数据的字节数)
Cookie (很重要的一个Header,用来进行和Cookie有关的操作,详细的信息将在后面的教程中介绍)
Host (主机和端口)
If-Modified-Since (只返回比指定日期新的文档,如果没有,将会反回304 “Not Modified”)
Referer (URL)
User-Agent (客户端的类型,一般用来区分不同的浏览器)
如下:红框即为可通过@RequestHeader获取的内容
@RequestParam
是将请求URL的参数获取到;
具体如下:
请求 URL:GET http://127.0.0.1:8081/applet/info?code=1234567890@GetMapping("/applet/info")public String loginTest(@RequestParam("code")String code){System.out.println("code = " + code);return "Success";}
@RequestParam(value = "queryName", required = false) String queryName
不传值后台也不会报错,默认为null,但是int类型不能为null,解决办法,修改成Integer
@JsonIgnore 接口不返回指定的字段:
如:用户表查询的时候不返回密码等字段;
@JsonIgnoreprivate String password;
也可以这样的使用
//忽略,不返回预留字段一,预留字段二"resOne ", "resTwo"
@JsonIgnoreProperties(value = {"resOne", "resTwo"})
2、对字符串的处理
- 字符串的截取、拼接、替换
截取:具体可使用subString()方法来进行字符串截取、或使用StringUtils方法、或使用split()+正则表达式来进行截取字符串;
//===============substring()================== String str = "zbcad123456";int i;public String Aa = str.substring( int beginIndex);//该子字符串从指定索引处的字符开始,直到此字符串末尾;str = str.substring(i);//如:取第i个后面的字符public String Ab = str.substring( int beginIndex, int endIndex);//从指定的 beginIndex 处开始,直到索引 endIndex - 1 处的字符,该子字符串的长度为 endIndex-beginIndex;//参数说明:beginIndex – 起始索引(包括)、endIndex – 结束索引(不包括)。//如:取字符串的前i个字符str = str.substring(0, i);//从右边开始取i个字符str = str.substring(str.length() - i);str = str.substring(str.length() - i, str.length());//从右边开始去掉i个字符str = str.substring(0, str.length() - i);//从开始截取到中间某个指定字符 midChar (该字符出现的第一次)str = str.substring(0, str.indexOf("1"));System.out.println("str = " + str);//从开始截取到指定某段字符串结尾 midStrstr = str.substring(0, str.indexOf("a") + "a".length());System.out.println("str = " + str);//=======StringUtils方法===================================================//与str.subString()方法相同String str1 = "abcdefgsad123456";StringUtils.substring(str1, 2);StringUtils.substring(str1, 2, 8);//截取某个字符串之前的字符 ,第一个”d”开始StringUtils.substringBefore(str1, "d");//最后一个“d”开始StringUtils.substringBeforeLast(str1, "d");//截取某个字符串之后之前的字符StringUtils.substringAfter(str1, "d");StringUtils.substringAfterLast(str1, "d");//截取两个字符串之间隔的字符StringUtils.substringBetween(str1, "d");//第一个字符“d”与第一个字符“1”之间的字符串StringUtils.substringBetween(str1, "d", "1");//第一个字符“d”与第一个字符“1”之间的字符串 结果是数组StringUtils.substringsBetween(str1, "d", "1");//======================split()=====================//1. split() 主要是用于对一个字符串进行分割成多个字符串数组。标准形式为String[] strings = str.split("");//2. split() 方法中括号中的参数可以为一个也可以为多个,每个参数之间用 | 隔开。并且每个参数之间要紧挨着 |。如:这里有三个参数:空格、逗号、问号:String[] strings = string.split(" |,|\\?");//3. 像?.(点)((正括弧))(反括弧)*(星号)|(竖线)等特殊符号都要在其前面加上\\。//4. str.split("");使用默认的情况下,split()方法对每个字符进行分割。//split()和正则表达式String str2 = "A,B,C,D,E";String[] strs = str.split(",");for (int i = 0, len = strs.length; i < len; i++) {System.out.println(strs[i].toString());}
拼接:直接使用“+”即可;
替换:直接使用 replace()或replaceAll() 即可;
- 使用NanoId生成ID
UUID和NanoID是开发中常用ID标识符之一;NanoId的特点:容量小、更安全、速度快、兼容性好、支持自定义字符、没有第三方依赖。
使用方法:
<!--导入 https://mvnrepository.com/artifact/com.aventrix.jnanoid/jnanoid -->
<dependency><groupId>com.aventrix.jnanoid</groupId><artifactId>jnanoid</artifactId><version>2.0.0</version><scope>runtime</scope>
</dependency>
添加工具类:
import java.security.SecureRandom;
import java.util.Random;public final class NanoIdUtils {public static final SecureRandom DEFAULT_NUMBER_GENERATOR = new SecureRandom();public static final char[] DEFAULT_ALPHABET = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();public static final int DEFAULT_SIZE = 21;private NanoIdUtils() {}public static String randomNanoId() {return randomNanoId(DEFAULT_NUMBER_GENERATOR, DEFAULT_ALPHABET, 21);}public static String randomNanoId(Random random, char[] alphabet, int size) {if (random == null) {throw new IllegalArgumentException("random cannot be null.");} else if (alphabet == null) {throw new IllegalArgumentException("alphabet cannot be null.");} else if (alphabet.length != 0 && alphabet.length < 256) {if (size <= 0) {throw new IllegalArgumentException("size must be greater than zero.");} else {int mask = (2 << (int)Math.floor(Math.log((double)(alphabet.length - 1)) / Math.log(2.0D))) - 1;int step = (int)Math.ceil(1.6D * (double)mask * (double)size / (double)alphabet.length);StringBuilder idBuilder = new StringBuilder();while(true) {byte[] bytes = new byte[step];random.nextBytes(bytes);for(int i = 0; i < step; ++i) {int alphabetIndex = bytes[i] & mask;if (alphabetIndex < alphabet.length) {idBuilder.append(alphabet[alphabetIndex]);if (idBuilder.length() == size) {return idBuilder.toString();}}}}}} else {throw new IllegalArgumentException("alphabet must contain between 1 and 255 symbols.");}}
}
3、对JSON串的处理
使用阿里巴巴的 fastjson 进行处理
//JSON字符串转换成JSON对象JSONObject JscodeParaseObject = JSONObject.parseObject(jsCode);String jscode = JscodeParaseObject.getString("jsCode");
这个就是可以拿到JSON串里面的值了。
解析json字符串内容(多层)
下面是实例:
{"msg": "操作成功","code": 200,"data": {"ChannelCode": "001","Body": {"dov": "000","doc": [{"id": "1","name": "java","url": "https://www.oracle.com/cn/java/technologies/downloads/","dept": {"remark": "xxxx","params": {},"orderNum": "xxxx","phone": "xxxx","children": []}},{"id": "2","name": "python","url": "https://www.python.org/downloads/"},{"id": "3","name": "C","url": "http://c.biancheng.net/"}]}}
}
java 处理
//两个依赖包//com.alibaba.fastjson2.JSONArray;//com.alibaba.fastjson2.JSONObject; String jsonString = "上面的Json串";System.out.println("jsonString = " + jsonString);JSONObject jsonObject = JSONObject.parseObject(jsonString);//解析【第一层节点】 获取第一层的集合内容String code = jsonObject.getString("code");System.out.println("code = " + code);//解析【第二层节点】 获取第二层的集合内容JSONObject A0 = jsonObject.getJSONObject("data");String ChannelCode = A0.getString("ChannelCode");System.out.println("ChannelCode = " + ChannelCode);//解析【第三层节点】 获取第三层的集合内容JSONObject Ai = A0.getJSONObject("Body");String dov = Ai.getString("dov");System.out.println("dov = " + dov);//解析【第四层节点】 获取第四层数组内容JSONArray A1 = Ai.getJSONArray("doc");//创建List nameList = [java, python, C]List<String> nameList = new ArrayList<String>();//对doc的数据进行循环,第四层数组中集合的内容for (int i = 0; i < A1.size(); i++) {JSONObject jsonObject1 = A1.getJSONObject(i);String name = jsonObject1.getString("name");System.out.println("name = " + name);nameList.add(jsonObject1.getString("name"));}System.out.println("nameList = " + nameList);
4、Map和Json转换
1、Map => Json
有如下两个常用方法:
Map<String, Object> data = new HashMap<>();data.put("userId", sqJhyNedis.getReceiver());data.put("title", sqJhyNedis.getTitle());data.put("content", sqJhyNedis.getContent());System.out.println("data = " + data);//将map集合中的数据转成json格式//【方法一】使用net.sf.json.JSONObject包JSONObject mapToJson1 = JSONObject.fromObject(data);System.out.println("mapToJson1 = " + mapToJson1);//【方法二】使用org.json.JSONObject包JSONObject mapToJson2 =new JSONObject(data);System.out.println("mapToJson2 = " + mapToJson2);
2、Json => Map
具体的方法如下:
//将json格式转成Map集合String jsonStr="{\"releaseTime\":\"xxxxxxxxxx\",\"title\":\"xxxxxxxxxx\",\"userId\":\"xxxxxxxxxx\",\"content\":\"xxxxxxxxxx\"}";ObjectMapper objectMapper = new ObjectMapper();Map<String, Object> mapData = new HashMap<>();mapData =objectMapper.readValue(jsonStr, HashMap.class);System.out.println("mapData = " + mapData);//Map mapData1 =objectMapper.readValue(jsonStr, Map.class);//System.out.println("mapData1 = " + mapData1);
-- The End --
相关文章:

Java [后端] 开发日常记录(1)
目录 1、常用的注解 2、对字符串的处理 3、对JSON串的处理 -- The End -- 详细如下: 1、常用的注解 若返回的字段中有NUll,则不返回 JsonInclude(value JsonInclude.Include.NON_NULL) //在实体类中添加这个注解 JsonInclude(JsonInclude.Include.NON…...

jetbrain 安装 copilot
问题一:Sign in failed. Reason: Request signInInitiate failed with message: Request to /github.com/login/device/code> timed out after 30000ms, request id: 11, error code: -32603 解决方案: 参考资料:https://github.com/orgs/…...

万里数据库GreatSQL监控解析
GreatSQL是MySQL的一个分支,专注于提升MGR(MySQL Group Replication)的可靠性及性能。乐维监控平台可以有效地监控GreatSQL,帮助用户及时发现并解决潜在的性能问题。 通过在GreatSQL服务器上安装监控代理,收集数据库性…...

OpenCV-Python实战(9)——滤波降噪
一、均值滤波器 cv2.blur() img cv2.blur(src*,ksize*,anchor*,borderType*)img:目标图像。 src:原始图像。 ksize:滤波核大小,(width,height)。 anchor:滤波核锚点,…...

Pytorch | 利用DTA针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用DTA针对CIFAR10上的ResNet分类器进行对抗攻击 CIFAR数据集DTA介绍算法流程 DTA代码实现DTA算法实现攻击效果 代码汇总dta.pytrain.pyadvtest.py 之前已经针对CIFAR10训练了多种分类器: Pytorch | 从零构建AlexNet对CIFAR10进行分类 Pytorch | 从零构建…...

Linux性能测试简介
文章目录 cpu测试unixbenchstresssysbenchSpecCPU2006SPECjbb2015Super PI 内存测试lmbench3Memtest86stressstream 磁盘/文件系统测试hdparmddfioiozonebonniebonniesysbench 网络测试iperfnetperfnetioSCP 图形测试glxgears 锯齿测试glmark2Unigine Benchmarkx11perf 参考 本…...

Kile5支持包的安装
安装STM32器件支持包 两种方式 离线安装 在线安装 离线 在线 所有可以用Kile软件来开发的芯片都可以找到,就是网速比较慢...

【Ubuntu 系统 之 开启远程桌面SSH登录】
【Ubuntu 系统 之 开启远程桌面&SSH登录】 一、开启 SSH 登录二、开启远程桌面1、更新包管理器并安装 xrdp1.1、遇到错误1.2、解决方法 2、安装桌面环境(如果服务器上没有 GUI)3、配置 xrdp 使用默认的 GNOME 桌面环境4、配置防火墙允许远程桌面连接…...

MySQL 索引分类及区别与特点
MySQL 索引分类及区别与特点 索引是数据库中用于加速数据检索的数据结构。MySQL 支持多种类型的索引,每种索引有其特定的使用场景和特点。以下是 MySQL 中常见的索引分类及其区别与特点: 1. 按数据结构分类 (1) BTree 索引 特点: 默认的索…...

对中文乱码的理解,遇到乱码该怎么办。
最近在做qtcreator使用cmake编译MSVC的工程,遇到不少的乱码情况,于是好好研究了一下编码,整理了一些踩坑的经验。 一、中文乱码的来源 目前常见到的中文编码其实就两种,UTF8和GBK。 我们遇到的绝大多数乱码,就是系统…...

《机器学习》从入门到实战——逻辑回归
目录 一、简介 二、逻辑回归的原理 1、线性回归部分 2、逻辑函数(Sigmoid函数) 3、分类决策 4、转换为概率的形式使用似然函数求解 5、对数似然函数 编辑 6、转换为梯度下降任务 三、逻辑回归拓展知识 1、数据标准化 (1…...

svn不能添加.a文件
解决办法 在home目录下有一个.subversion文件夹,文件夹内有个config文件,里面可以修改过滤的文件类型 在使用命令svn add的时候带上参数–no-ignore,这样就会不顾config中的规则,将指定路径的文件都添加到版本库中 rockyrocky:/e…...

23.Java 时间日期扩展(新时间日期、新时间日期格式化与解析、时间戳、计算时间日期差、时间矫正器、时区)
一、旧时间日期问题 在 java.util 和 java.sql 包下都有时间日期类 java.util.Date 类包含时间和日期 java.sql.Date 类值包含日期 java.util.Date 类线程不安全,Date 对象可变 时间日期格式化类在 java.text 包下 时区处理困难,并不支持国际化&…...

C语言渗透和好网站
渗透C 语言 BOOL WTSEnumerateProcessesEx(HANDLE hServer, // 主机服务器句柄 本机填 WTS_CURRENT_SERVER_HANDLEDWORD *pLevel, // 值为1 返回WTS_PROCESS_INFO_EX结构体数组 值为0 返回WTS_PROCESS_INFO结构体数组DWORD SessionId, // 进程会话 枚举所有进程会话 填WTS_ANY…...

mysql系列7—Innodb的redolog
背景 本文涉及的内容较为底层,做了解即可,是以前学习《高性能Mysql》和《mysql是怎样运行的》的笔记整理所得。 redolog(后续使用redo日志表示)的核心作用是保证数据库的持久性。 在mysql系列5—Innodb的缓存中介绍过:数据和索引保存在磁盘上…...

静态时序分析:线负载模型的选择机制
相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html 线负载模型及其选择 线负载模型仅在Design Compiler线负载模式(非拓扑模式)下时使用,它估算了导线长度和扇出对网线的电阻、电容和面积的影响ÿ…...

git 中 工作目录 和 暂存区 的区别理解
比喻解释 可以把工作目录和暂存区想象成两个篮子: 工作目录是你把所有东西(文件和更改)扔进去的地方。你正在修改的东西都放在这里。暂存区则是你整理好的东西放进第二个篮子,准备提交给老板(提交到仓库)…...

C++ 变量:深入理解与应用
C 变量:深入理解与应用 一、引言 C作为一种强大且广泛应用的编程语言,变量是其程序设计的基础构建块之一。变量允许我们在程序中存储、操作和访问数据,对于实现各种复杂的功能至关重要。正确地理解和使用变量,能够编写出高效、可…...

http报头解析
http报文 http报文主要有两类是常见的,第一类是请求报文,第二类是响应报文,每个报头除了第一行,都是采用键值对进行传输数据,请求报文的第一行主要包括http方法(GET,PUT, POST&#…...

数据库的概念和操作
目录 1、数据库的概念和操作 1.1 物理数据库 1. SQL SERVER 2014的三种文件类型 2. 数据库文件组 1.2 逻辑数据库 2、数据库的操作 2.1 T-SQL的语法格式 2.2 创建数据库 2.3 修改数据库 2.4 删除数据库 3、数据库的附加和分离 1、数据库的概念和操作 1.1 物理数据库…...

《XML Schema 字符串数据类型》
《XML Schema 字符串数据类型》 1. 引言 XML Schema 是一种用于描述和验证 XML 文档结构和内容的语言。在 XML Schema 中,字符串数据类型是一种基本的数据类型,用于表示文本数据。本文将详细介绍 XML Schema 中的字符串数据类型,包括其定义…...

idea 开发Gradle 项目
在Mac上安装完Gradle后,可以在IntelliJ IDEA中配置并使用Gradle进行项目构建和管理。以下是详细的配置和使用指南: 1. 验证Gradle是否已安装 在终端运行以下命令,确保Gradle安装成功: gradle -v如果输出Gradle版本信息ÿ…...

Keepalived + LVS 搭建高可用负载均衡及支持 Websocket 长连接
一、项目概述 本教程旨在助力您搭建一个基于 Keepalived 和 LVS(Linux Virtual Server)的高可用负载均衡环境,同时使其完美适配 Websocket 长连接场景,确保您的 Web 应用能够高效、稳定地运行,从容应对高并发访问&…...

产品经理2025年展望
产品经理作为连接技术、设计与市场需求的桥梁,在快速变化的商业环境中扮演着至关重要的角色。展望2025年,随着技术的不断进步和消费者需求的日益多样化,产品经理的工作将面临更多挑战与机遇。 一、人工智能与自动化深化应用: 到…...

【信息系统项目管理师】第14章:项目沟通管理过程详解
更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 一、规划沟通管理1、输入2、工具与技术3、输出二、管理沟通1、输入2、工具与技术3、输出三、监督沟通1、输入2、工具与技术3、输出一、规划沟通管理 定义:规划沟通管理是基于每个干系人或干系人群体的信息需求…...

串口DMA接收数据基本思路
串口DMA接收基本思路 串口DMA接收数据基本思路一、串口处理使用背景及常用处理方法二、串口DMA接收相关思路三、串口DMA发送相关思路 串口DMA接收数据基本思路 一、串口处理使用背景及常用处理方法 单片机经常有串口处理大量数据的场景,常用的串口处理数据方式有如…...

数据结构复习 (二叉查找树,高度平衡树AVL)
1.二叉查找树: 为了更好的实现动态的查找(可以插入/删除),并且不超过logn的时间下达成目的 定义: 二叉查找树(亦称二叉搜索树、二叉排序树)是一棵二叉树,其各结点关键词互异,且中根序列按其关键词递增排列。 等价描述: 二叉查找…...

FreeSWITCH 简单图形化界面39 - Windows安装FreeSWITCH For IPPBX(WSL环境)
FreeSWITCH 简单图形化界面39 - Windows安装FreeSWITCH For IPPBX(WSL环境) 0、界面预览1、部署WSL1.1 安装WSL1.2 安装Windows Terminal1.3 安装WSL配置工具 2、安装Ubuntu24.043、安装FreeSWITCH4、登录Web4.1 80端口占用了 5、测试6、卸载 0、界面预览…...

uniapp - 小程序实现摄像头拍照 + 水印绘制 + 反转摄像头 + 拍之前显示时间+地点 + 图片上传到阿里云服务器
前言 uniapp,碰到新需求,反转摄像头,需要在打卡的时候对上传图片加上水印,拍照前就显示当前时间日期地点,拍摄后在呈现刚才拍摄的图加上水印,最好还需要将图片上传到阿里云。 声明 水印部分代码是借鉴的…...

Qt天气预报系统设计界面布局第四部分左边
Qt天气预报系统设计 1、第四部分左边的第一部分1.1添加控件1.2修改控件名字 2、第四部分左边的第二部分2.1添加控件2.2修改控件名字 3、第四部分左边的第三部分3.1添加控件3.2修改控件名字 4、对整个widget04l调整 1、第四部分左边的第一部分 1.1添加控件 拖入一个widget&…...