代码拉取完成,页面将自动刷新
{"meta":{"title":"Gendml","subtitle":"Gendml的博客空间","description":"Graduate Student | NEU | Personal Notes","author":"Gendml","url":"https://gend-max.gitee.io","root":"/"},"pages":[{"title":"404","date":"2022-05-12T01:31:36.000Z","updated":"2022-05-16T23:41:33.798Z","comments":true,"path":"404/index.html","permalink":"https://gend-max.gitee.io/404/index.html","excerpt":"","text":""},{"title":"","date":"2022-05-12T01:21:48.000Z","updated":"2023-02-20T08:00:38.107Z","comments":true,"path":"about/index.html","permalink":"https://gend-max.gitee.io/about/index.html","excerpt":"","text":""},{"title":"归档","date":"2022-08-18T11:27:44.000Z","updated":"2022-08-18T12:10:48.699Z","comments":true,"path":"archives/index.html","permalink":"https://gend-max.gitee.io/archives/index.html","excerpt":"","text":""},{"title":"contact","date":"2022-05-12T01:22:10.000Z","updated":"2022-05-16T23:41:34.302Z","comments":true,"path":"contact/index.html","permalink":"https://gend-max.gitee.io/contact/index.html","excerpt":"","text":""},{"title":"分类","date":"2022-05-12T01:19:46.000Z","updated":"2022-08-18T12:10:57.416Z","comments":true,"path":"categories/index.html","permalink":"https://gend-max.gitee.io/categories/index.html","excerpt":"","text":""},{"title":"musics","date":"2022-05-12T05:22:51.000Z","updated":"2022-05-17T12:59:05.892Z","comments":true,"path":"musics/index.html","permalink":"https://gend-max.gitee.io/musics/index.html","excerpt":"","text":""},{"title":"便笺","date":"2022-08-18T10:54:21.000Z","updated":"2022-08-19T09:42:28.701Z","comments":true,"path":"note/index.html","permalink":"https://gend-max.gitee.io/note/index.html","excerpt":"","text":"开发必备国内CDN加速https://www.bootcdn.cn/清华大学开源软件镜像站https://mirrors.tuna.tsinghua.edu.cn/DaoCloud镜像市场https://hub.daocloud.io/Docker Hubhttps://hub.docker.com/Maven Repositoryhttps://mvnrepository.com/ 技术手册Java全栈知识体系Java面试手册CS-NotesCS学习笔记CS-Books超过1000本的计算机经典书籍分享编程导航IT全栈资源RunOOB菜鸟教程C语言中文网http://c.biancheng.net/易百教程https://www.yiibai.com/廖雪峰的官方网站https://www.liaoxuefeng.com/W3CschoolW3Cschool编程狮 行业大佬Road To CodingCodeSheep搭建的资源学习网OneV's Den上善若水,人淡如菊 设计灵感、素材和工具SCI-HUBthe first pirate website in the world to provide mass and public access to tens of millions of research papersJiumo Search文档搜索引擎果核剥壳https://www.ghxi.com/wallhavenThe best wallpapers on the Net!UnsplashPhotos for everyone.Iconfont阿里巴巴矢量图标库PPT超级市场https://www.pptsupermarket.com/100font个专门收集整理“免费商用字体”的网站耳聆网听见世界之美 - (声音分享云|音效素材库)Free video clipsFree Stock Video Footage HD Royalty-Free Videos Download"},{"title":"movies","date":"2022-05-12T05:23:04.000Z","updated":"2022-05-16T23:41:34.398Z","comments":true,"path":"movies/index.html","permalink":"https://gend-max.gitee.io/movies/index.html","excerpt":"","text":""},{"title":"标签","date":"2022-05-12T01:21:20.000Z","updated":"2022-08-18T12:11:12.384Z","comments":true,"path":"tags/index.html","permalink":"https://gend-max.gitee.io/tags/index.html","excerpt":"","text":""},{"title":"Stellar主题配置","date":"2022-08-18T14:44:15.705Z","updated":"2022-08-18T14:44:15.705Z","comments":true,"path":"wiki/stellar/index.html","permalink":"https://gend-max.gitee.io/wiki/stellar/index.html","excerpt":"","text":"快速开始您的博客之旅Stellar 是一个内置 wiki 系统的 hexo 主题,拥有简约而精美的视觉设计和丰富又灵活的标签插件,帮助您简单从容地应对各种表达需求,十分推荐内容创作者使用 Stellar 开始您全新的博客之旅。 了解 Stellar 的设计理念“真正的简约远不止删繁就简,而是在纷繁中建立秩序。”人的注意力是有限的,要提高有效信息的醒目程度,就必须降低不重要信息醒目程度,删除所有无效信息。降低视觉密度增加留白,增加间距。减少颜色丰富度,大面积出现的是中性色,彩色必须有其特殊意义,意义相同的元素使用同一种颜色。提高有效信息优先级文章标题永远是最大的,对比度最高的不可交互的不重要的小标题(如侧边栏某个插件的标题)降低对比度与文章相关的不重要的小标题,使用小号字体删掉无效信息文章标签、字数、阅读量、评论数网站访问量、字数、搭建时间全局播放器(除了特殊文章) 开始前的准备工作尽管我们致力于降低使用门槛,但是自建独立博客仍然需要一定的相关知识,markdown 常用语法是必须要掌握的,除此之外,您还需要知道 yaml 文件格式、简单的 git 知识,最最重要的是,遇到问题知道该如何高效地寻找答案: 翻阅和搜索文档 搜索 issues 中是否已经有解决办法 如果没有,新建 issue 并按照要求进行操作,详尽地描述您遇到的问题 如果您没有使用过 Hexo 也不要着急,可以先通读一遍 Hexo 中文文档。此外,如果您从旧版本更新或着其它主题迁移,请确保环境版本不要太低,否则会产生兼容性问题: 建议的版本Hexo: 5.4.0 ~ 6.2.0 hexo-cli: 4.3.0 ~ latest node.js: 14.17.3 ~ 16.15.0 # 建议选择 LTS 版本,过高的版本 hexo 还没有进行兼容。 npm: 6.14.13 ~ 8.5.5"}],"posts":[{"title":"【文献阅读】【综述】UAV-assisted mobile edge computing","slug":"【文献阅读】【综述】:UAV-assisted mobile edge computing","date":"2023-11-08T15:22:48.000Z","updated":"2023-11-08T15:22:54.474Z","comments":true,"path":"2023/11/08/wen-xian-yue-du-zong-shu-uav-assisted-mobile-edge-computing/","link":"","permalink":"https://gend-max.gitee.io/2023/11/08/wen-xian-yue-du-zong-shu-uav-assisted-mobile-edge-computing/","excerpt":"","text":"《Aerial Edge Computing A Survey》 作者:Qinglou Zhang et al. 发表时间:2023年8月 来源:IEEE INTERNET OF THINGS JOURNAL(JCR Q1)(Top)(中科院1区) 关键字:空中边缘计算(AEC)、移动边缘计算、服务质量(QoS)、无线通信网络。 《AI for UAV-Assisted IoT Applications》 作者:Nan Cheng et al. 发表时间:2023年8月 来源:IEEE INTERNET OF THINGS JOURNAL(JCR Q1)(Top)(中科院1区) 关键字:人工智能(AI)、物联网(IoT)、强化学习(RL)、无人机应用、无人机(UAV)。 1、研究背景无人机在物联网中的应用 随着物联网的发展,无人机凭借着其灵活性、可操作性和经济性在各行各业中得到了广泛地应用 农业:通过部署无人机来监测农作物生长、喷洒农药以及实现农场自动化以实现智能农业 紧急场景:无人机可以提供通信服务、物资运送和环境监控 城市:通过无人机实现视频监控、打造智能交通系统(ITSs)和提供医疗保健服务 现代战争:例如,在俄乌战场中,使用了大量的军用无人机提供通信、侦察和攻击服务 无人机辅助应用场景:农业、紧急场景、城市、现代战争 无人机辅助移动边缘计算 传统移动边缘计算(MEC)场景中,移动设备可以卸载本地任务至边缘服务器,从而降低延迟和能耗 然而,受基站、边缘节点与本地设备距离等因素的影响,有时无法为通信拥堵和连接有限的地区提供良好的网络服务质量(QoS) 通过将边缘服务器配备在无人机上,可以将其充当飞行基站和边缘计算节点,凭借其灵活性快速形成自组织网络,为通信受限的地区提供及时的网络服务 无人机辅助下的空中移动边缘计算 2、研究现状 带有MEC服务器的无人机相较于传统边缘计算服务器具有以下特点: 为了在有限资源下,提高QoS、降低延迟和提升能量效率,需要考虑以下四个方面: 高速可移动 计算卸载 能源有限 资源分配 与移动设备(MDs)的距离通常较近 路径规划 … 能量控制 以下是目前已知的解决方法: 使用多智能体强化学习(MARL)求解以上问题的联合优化 尝试其他网络接入模式降低通信延迟,例如非正交多址(NOMA)、时分多址(TDMA) 在飞行轨迹规划和网络调度上,分别使用深度强化学习(DRL)与其他方法相结合,例如启发式算法…… 3、未来挑战无人机的训练问题 在训练过程中,通常需要智能体与环境不断交互获得训练数据,数据可能存在冗余、标签(奖励)错误和类别不平衡等问题,通常使用数据增强可以解决数据匮乏与收敛问题。 作者提出使用联邦学习(FL),以去中心化的方式,通过局部、全局的交互更新模型参数。这样训练数据较少的无人机可以通过其他无人机的训练结果更新本地模型,以保证训练的有效性。 无人机的收敛问题 由于单架无人机的服务能力有限,无法满足某些场景用户的需求。在大规模无人机场景下,通常智能体的状态和动作空间维度会呈指数型增长,造成“维度灾难”,导致算法难以收敛和学习效率低下等问题。 作者提出使用图神经网络(GNN)处理大规模场景方面可能具有良好的效果。 无人机的资源和能源限制问题 由于单架无人机的服务能力有限,无法满足某些场景用户的需求。在大规模无人机场景下,通常智能体的状态和动作空间维度会呈指数型增长,造成“维度灾难”,导致算法难以收敛和学习效率低下等问题。 作者提出使用图神经网络(GNN)处理大规模场景方面可能具有良好的效果。 无人机的安全和隐私问题 联邦学习(FL)通过分布式模型训练,通过局部参数构建全局模型,这种方式可以做到保护用户数据隐私和安全。","categories":[{"name":"文献阅读-综述-无人机辅助MEC","slug":"文献阅读-综述-无人机辅助MEC","permalink":"https://gend-max.gitee.io/categories/%E6%96%87%E7%8C%AE%E9%98%85%E8%AF%BB-%E7%BB%BC%E8%BF%B0-%E6%97%A0%E4%BA%BA%E6%9C%BA%E8%BE%85%E5%8A%A9MEC/"}],"tags":[{"name":"文献阅读-综述","slug":"文献阅读-综述","permalink":"https://gend-max.gitee.io/tags/%E6%96%87%E7%8C%AE%E9%98%85%E8%AF%BB-%E7%BB%BC%E8%BF%B0/"},{"name":"无人机辅助MEC","slug":"无人机辅助MEC","permalink":"https://gend-max.gitee.io/tags/%E6%97%A0%E4%BA%BA%E6%9C%BA%E8%BE%85%E5%8A%A9MEC/"}],"author":"Gendml"},{"title":"Docker学习笔记","slug":"Docker学习笔记","date":"2022-08-06T17:55:29.000Z","updated":"2024-04-17T13:20:00.480Z","comments":true,"path":"2022/08/07/docker-xue-xi-bi-ji/","link":"","permalink":"https://gend-max.gitee.io/2022/08/07/docker-xue-xi-bi-ji/","excerpt":"","text":"一、DockerDocker命令大全 (一)常用命令新建容器docker run -itd --privileged=true --name <你的容器名字> -p 6000(你的电脑端口):6000(对应映射容器的端口)(可以进行多个端口映射) centos(用哪种镜像创建):7(镜像的Tag) /usr/sbin/init(表示使用bash进行命令操作) -i: 以交互模式运行容器,通常与 -t 同时使用; -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用 docker run -itd --privileged=true --name my_centos7 -p 50001:22 -p 50002:3306 centos:7 /usr/sbin/init 关于docker镜像内安装命令apt-get update && apt-get install lrzsz yum -y(安装时自动选择yes) update 查看容器状态docker ps -a 暂停容器docker stop <容器ID> 运行容器(stop的容器再次启动)docker start <容器ID> 查看本地镜像docker images 拉取镜像docker pull +镜像名称 连接运行的容器docker attach +容器 可以同时连接上同一个container来共享屏幕(与screen命令的attach类似) 使用 Ctrl + p + q 退出,直接使用Ctrl + c会导致容器本身也停止 查看容器运行的进程 得到PID后,在宿主机上执行操作 docker top +容器名称 在容器中执行命令docker exec -it <容器ID> /bin/bash 从容器创建一个新的镜像docker commit -a \"作者名称\" -m \"携带消息\" <容器名> centos(镜像):ssh(标签) eg:docker commit -a \"Gendml\" -m \"已配置ssh的CentOS7镜像\" Gendml_Centos7 centos:ssh 容器与主机之间的数据拷贝docker cp /www/runoob 96f7f14e99ab:/www docker cp 96f7f14e99ab:/www /tmp/ 容器与宿主映射添加容器卷docker run -itd --privileged=true --name 容器名称 -v /宿主机绝对路径目录:/容器内目录 -p 端口映射 镜像名 配置读写规则 默认是读写 配置只读规则:docker run -it --privileged=true -v/宿主机绝对路径目录:/容器内目录:ro 镜像名 容器2继承容器1的卷规则 效果:容器之间卷数据映射,无论容器是否运行,实时卷同步 docker run-it --privileged=true --volumes-from 父类 --name u2 ubuntu Docker导出容器作为tar归档文件docker export -o xxx.tar <容器名称> bash(不加会出bug) Docker从归档文件中导入镜像docker import xxx.tar 镜像名称:标签 Docker挂载主机目录访问如果出现cannot open directory .: Permission denied 解决办法:在挂载目录后多加一个–privileged=true参数即可 如果是CentOS7安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载的情况被默认为不安全的行为 在SELinux里面挂载目录被禁止掉了额,如果要开启,我们一般使用–privileged=true命令,扩大容器的权限解决挂载目录没有权限的问题,也即使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。 Docker网络 Docker网络作用: 容器间的互联和通信以及端口映射 容器IP变动时候可以通过服务名直接网络通信而不受到影响 网络模式 bridge模式:使用–network bridge指定,默认使用docker0 Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。 host模式:使用–network host指定(-p端口映射失效,开启后要关闭虚拟机的防火墙) 直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。 none模式:使用–network none指定 在none模式下,并不为Docker容器进行任何网络配置。 也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo 需要我们自己为Docker容器添加网卡、配置IP等。 container模式:使用–network container:NAME或者容器ID(多个容器间通信) 新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。 docker run -d -p 8085:8080 --name tomcat85 billygoo/tomcat8-jdk8 docker run -d -p 8086:8080 --network container:tomcat85 --name tomcat86 billygoo/tomcat8-jdk8 自定义网络 Docker的–link参数已经过时,即将被Docker弃用 Docker容器之间可以通过ip地址ping通 但是,一旦某个容器宕机,其他新建的容器会占用宕机容器的ip地址,原容器的功能会出现错乱,这对于大型微服务开发是致命的 自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通),容器名称可直接作ip地址使用。 docker network create XXX网络名字 安装ping命令apt-get update apt install -y iputils-ping 安装ip addr命令apt-get update apt install -y iproute2 安装ifconfig命令apt-get update apt install -y net-tools 查看网络docker network ls 查看单个Docker容器网络地址ip addr 查看网络源数据docker network inspect XXX网络名字 删除网络docker network rm XXX网络名字 Docker配置Jetty容器创建容器docker run -itd --name gendml_jetty --privileged=true --network gendml_net -p 50001:8080 -v /usr/Docker/jetty/webapps:/var/lib/jetty/webapps jetty:9.4.48-jdk8 Docker配置Nginx容器创建容器docker run -itd --name gendml_nginx_student --privileged=true --network gendml_net -p 50004:9000 -v /usr/Docker/nginx_student/config/nginx.conf:/etc/nginx/nginx.conf -v /usr/Docker/nginx_student/html:/usr/share/nginx/html nginx:1.20.1 Docker配置JDK18容器创建容器docker run -itd --name gendml_java --privileged=true --network host -v /usr/Docker/java:/usr/java/project openjdk:jdk-oraclelinux8 查看防火墙状态systemctl status firewalld 开机关闭防火墙systemctl disable firewalld.service 关闭防火墙systemctl stop firewalld.service Docker配置MySQL容器创建容器docker run # 创建容器 -itd # 交互式后台运行 --name gendml_mysql # 容器名称 --privileged=true # 特权模式,root --network gendml_net # 选择自定义网络 -p 50002:3306 # 端口映射(宿主:容器) -e MYSQL_ROOT_PASSWORD=dml666 # MySQL密码 -v /usr/Docker/mysql/log:/var/log/mysql # 资源共享 -v /usr/Docker/mysql/data:/cvar/lib/mysql # 资源共享 -v /usr/Docker/mysql/conf:/etc/mysql/conf.d # 资源共享 mysql:5.6.51 # 使用对应镜像创建容器 docker run -itd --name gendml_mysql --privileged=true --network gendml_net -p 3306:3306 -e MYSQL_ROOT_PASSWORD=dml666 -v /usr/Docker/mysql/log:/var/log/mysql -v /usr/Docker/mysql/data:/cvar/lib/mysql -v /usr/Docker/mysql/conf:/etc/mysql/conf.d mysql:5.6.51 解决中文乱码cd /usr/Docker/mysql/conf # 在conf文件夹内创建my.cnf # 文件填入如下内容 [client] default_character_set=utf8 [mysqld] collation_server = utf8_general_ci character_set_server = utf8 docker restart gendml_mysql Docker配置Redisdocker run -itd --privileged=true --name gendml_redis --network gendml_net -p 50003:6379 -v /usr/Docker/redis/redis.conf:/etc/redis/redis.conf -v /usr/Docker/redis/data:/data redis:6.0.8 redis-server /etc/redis/redis.conf Docker配置Jupyter-labdocker run -itd --name gendml-jupyter --privileged=true --network host -v /usr/Docker/jupyter:/home/jovyan jupyter/base-notebook","categories":[{"name":"工具","slug":"工具","permalink":"https://gend-max.gitee.io/categories/%E5%B7%A5%E5%85%B7/"}],"tags":[{"name":"Docker","slug":"Docker","permalink":"https://gend-max.gitee.io/tags/Docker/"}],"author":"Gendml"},{"title":"Node.js基础","slug":"Node.js基础","date":"2022-08-06T17:53:21.000Z","updated":"2023-02-20T07:50:55.937Z","comments":true,"path":"2022/08/07/node.js-ji-chu/","link":"","permalink":"https://gend-max.gitee.io/2022/08/07/node.js-ji-chu/","excerpt":"","text":"一、Node.js(一)常用命令更改仓库这里使用淘宝镜像 npm config set registry https://registry.npm.taobao.org 查看当前仓库npm config get registry","categories":[{"name":"编程语言","slug":"编程语言","permalink":"https://gend-max.gitee.io/categories/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/"}],"tags":[{"name":"Node.js","slug":"Node-js","permalink":"https://gend-max.gitee.io/tags/Node-js/"}],"author":"Gendml"},{"title":"Linux命令大全","slug":"Linux命令大全","date":"2022-05-17T15:40:12.000Z","updated":"2024-04-28T05:47:31.140Z","comments":true,"path":"2022/05/17/linux-ming-ling-da-quan/","link":"","permalink":"https://gend-max.gitee.io/2022/05/17/linux-ming-ling-da-quan/","excerpt":"","text":"一、Linux系统技术(一)常用命令链接命令,是给系统中已有的文件指定另一个名称 常用参数-s-f 提示 ln [ 参数 ] 源文件 目的文件 例子 -d硬链接:硬链接文件与原始文件其实是同一个文件,只是名字不同 -s软链接: 等同于 Windows 系统下的快捷方式。仅仅包括所含链接文件的路径名字。因此能链接目录,也能跨文件系统链接。但是,当删除原始文件后,链接文件也将失效。 删除链接:unlink + 链接名 查找命令位置whereis + 命令 清除当前终端窗口clear 查看当前目录 查看名称:ls 详细查看:ll 显示当前位置pwd 解压sudo tar xf <压缩文件名> -C <目标文件夹路径> 或 unzip filename.zip 程序会将.zip文件内容提取到当前目录下 若需指定解压后的路径,则可以添加-d参数 若不打印输出信息,则添加参数 -q参数 退出命令行ctrl+z 进入超级管理员模式sudo -i 进入用户模式su <用户名> 改变权限命令 chmod -R 777 <文件/目录>(!!!!!!慎用,如果对大范围系统根目录使用,是很危险的!!!) 常用参数:(1=执行权 2=写权 4=读权 1+2=3 执行和写权,以此类推) 提示:chmod <参数> <权限值> <文件或目录名> 复制 常用参数:-i-f-r 提示:cp [ 参数 ] 源文件或目录 目的文件或目录 -i当目标文件存在时,系统提示是否拷贝 -f目标文件存在时不给提示直接拷贝 -r拷贝这个目录及目录里的所有文件和子目录 关机和重启shutdown reboot 文件操作修改文件vim + 文件路径 -> i键表示插入修改 -> 当插入完成,点击esc,接着英文状态下 shift+: ,左下方显示冒号。输入wq!强制保存退出 移动文件/重命名mv 【源文件路径】 【目的文件路径】 搜索文件find / -name + 【文件路径】 查找文件中的指定字符查看sneakers.txt文件中”coffee”的位置:grep coffee sneakers.txt 你就会看到文件中带有“coffee”的每一行。 删除文件rm -rf + 【文件路径】 文件夹操作删除文件夹rm -rf + 【文件夹】 进入某文件夹cd + 【文件路径】 创建文件夹mkdir + 【文件路径】 移动文件夹/重命名mv 【源文件路径】 【目的文件路径】 (二)进阶命令yum命令是一个在 Fedora 和 RedHat 以及 SUSE 中的 Shell 前端软件包管理器。提供了查找、安装、删除某一个、一组甚至全部软件包的命令。 yum语法:yum [options] [command] [package ...] options:可选,选项包括-h(帮助),-y(当安装过程提示选择全部为 “yes”),-q(不显示安装的过程)等等。 command:要进行的操作。 package:安装的包名。 yum常用命令: 列出所有可更新的软件清单命令:yum check-update 更新所有软件命令:yum update 仅安装指定的软件命令:**yum install ** 仅更新指定的软件命令:**yum update ** 列出所有可安裝的软件清单命令:yum list 删除软件包命令:**yum remove ** 查找软件包命令:**yum search ** 清除缓存命令: yum clean packages: 清除缓存目录下的软件包 yum clean headers: 清除缓存目录下的 headers yum clean oldheaders: 清除缓存目录下旧的 headers yum clean, yum clean all (= yum clean packages; yum clean oldheaders) :清除缓存目录下的软件包及旧的 headers apt命令在 Debian 和 Ubuntu 中的 Shell 前端软件包管理器。提供了查找、安装、删除某一个、一组甚至全部软件包的命令。 apt 语法:apt [options] [command] [package ...] options:可选,选项包括-h(帮助),-y(当安装过程提示选择全部为 “yes”),-q(不显示安装的过程)等等。 command:要进行的操作。 package:安装的包名。 apt常用命令: 列出所有可更新的软件清单命令:sudo apt update 升级软件包:sudo apt upgrade 列出可更新的软件包及版本信息:apt list –upgradeable 升级软件包,升级前先删除需要更新软件包:sudo apt full-upgrade 安装指定的软件命令:**sudo apt install ** 安装多个软件包:**sudo apt install ** 更新指定的软件命令:**sudo apt update ** 显示软件包具体信息,例如:版本号,安装大小,依赖关系等等:**sudo apt show ** 删除软件包命令:**sudo apt remove ** 清理不再使用的依赖和库文件: sudo apt autoremove 移除软件包及配置文件: **sudo apt purge ** 查找软件包命令: **sudo apt search ** 列出所有已安装的包:apt list –installed 列出所有已安装的包的版本信息:apt list –all-versions 加载到环境变量source + .sh文件 下载命令下载并以不同的文件名保存 wget -O [name] [下载链接URL] 例如: wget -O wordpress.zip http://www.minjieren.com/download.aspx?id=1080 查看进程以及对应进程号jps 查看内存使用情况top 通过按键”E“更换内存的单位(kb, mb, gb, tb …) 结束某个进程kill -9 + 进程号 后台挂起nohup java -jar jar包 >err.out(输出错误日志)& (让bash在后台运行) 运行jar包java -jar +jar包名称 查看所有端口进程netstat -nlp 检查文件系统的空间占用情况df -h:查看所有的文件系统的空间占用情况 df -h [目录]:查看当前目录所在的文件系统的空间占用情况 maven命令运行boot项目前提:安装Maven3.2.2(Windows上是此版本) mvn spring-boot:run 进程Kill杀死后GPU显存没有释放仍然被占用(僵尸进程)见CSDN博客","categories":[{"name":"操作系统","slug":"操作系统","permalink":"https://gend-max.gitee.io/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://gend-max.gitee.io/tags/Linux/"}],"author":"Gendml"},{"title":"Raspberry Pi使用总结","slug":"Raspberry Pi使用总结","date":"2022-05-17T15:40:12.000Z","updated":"2023-02-20T07:51:17.655Z","comments":true,"path":"2022/05/17/raspberry-pi-shi-yong-zong-jie/","link":"","permalink":"https://gend-max.gitee.io/2022/05/17/raspberry-pi-shi-yong-zong-jie/","excerpt":"","text":"一、树莓派常用命令打开树莓派配置sudo raspi-config 立即关机shutdown -h now 重启sudo reboot 查看插入设备的USB口lsusb 查看摄像头设备名ls /dev/video* 查看树莓派端口ls -l /dev/tty*","categories":[{"name":"单片机","slug":"单片机","permalink":"https://gend-max.gitee.io/categories/%E5%8D%95%E7%89%87%E6%9C%BA/"}],"tags":[{"name":"Raspberry Pi","slug":"Raspberry-Pi","permalink":"https://gend-max.gitee.io/tags/Raspberry-Pi/"}],"author":"Gendml"},{"title":"深度学习系列笔记","slug":"深度学习系列笔记","date":"2022-05-17T15:35:15.000Z","updated":"2023-02-20T07:51:36.652Z","comments":true,"path":"2022/05/17/shen-du-xue-xi-xi-lie-bi-ji/","link":"","permalink":"https://gend-max.gitee.io/2022/05/17/shen-du-xue-xi-xi-lie-bi-ji/","excerpt":"","text":"1、梯度下降法1.1梯度梯度是函数增长最快的方向,梯度的模为这一方向的变化率。 对于一元函数求梯度,公式为:$$\\frac{d y}{d x}=f^{\\prime}(x)=\\lim _{\\Delta x \\rightarrow 0} \\frac{\\mathrm{f}(\\mathrm{x}+\\Delta x)-f(x)}{\\Delta x}$$很显然,该函数的梯度为一条切线。 而对于多维函数,比如f(x,y),此函数的梯度为一个切面。 如果再进行维度拓展,将无法进行求解,科学家通过引入偏导,求解梯度: 1.2梯度下降法思路找到函数的梯度,在此方向取负梯度,函数下降的最快,进而找到函数的最小值,一般用于求解损失函数的最小值,优化模型。 2、Python中的广播2.1广播案例 当两个矩阵相加,在不符合线性代数矩阵运算时,矩阵会自动扩展结构,然后执行运算 2.2Numpy中的广播机制广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行。 如果两个数组 a 和 b 形状相同,即满足 a.shape == b.shape,那么 a*b 的结果就是 a 与 b 数组对应位相乘。这要求维数相同,且各维度的长度相同。 实例: import numpy as np a = np.array([[ 0, 0, 0], [10,10,10], [20,20,20], [30,30,30]]) b = np.array([1,2,3]) print(a + b) 输出结果: [[ 1 2 3] [11 12 13] [21 22 23] [31 32 33]] 下面的图片展示了数组 b 如何通过广播来与数组 a 兼容。 3、最小二乘法3.1什么是线性回归?比如,在二维空间中,线性回归就是要找一条直线,并且让这条直线尽可能拟合图中的数据点 每条红色竖线是预测数据到真实数据的差距(误差),称为欧氏距离,然后将这些误差加起来,就得到线性回归的损失函数。$$\\sum_{i=0}^{m} (y^{(i)} - \\hat{y} ^{(i)} )^{^{2} }$$ 3.2最小二乘法见知乎专栏 在实际观测时,考虑到观测值带有偶然误差,总是作多余观测。 4、最大似然估计见知乎专栏 最大似然估计可以说是应用非常广泛的一种参数估计的方法。它的原理也很简单:利用已知的样本,找出最有可能生成该样本的参数。 4.1什么是似然函数? 4.2最大似然估计 4.3离散型随机变量的最大似然估计 $$C_{n}^{k} = \\frac{n!}{k!(n-k)!}是二项式系数,我们希望有k次成功(p)和n−k次失败(1 −p),并且,k次成功可以在n次试验的任何地方出现,而把k次成功分布在n次试验中共有C_{n}^{k}个不同的方法。$$ 4.4连续型随机变量的最大似然估计 5、Logistic回归5.1Logistic回归如下图所示,计算节点值z,再通过激活函数sigmoid()求出a,a为到该节点的输出,如下图。 5.2Logistic回归再在神经网络的应用神经网络正向传播中执行了很多次类似Logistic回归的操作,如下图所示,每个节点执行了一次Logistic回归,舍弃for循环,通过矩阵运算快速计算出z(用z[1]表示)和a(用a[1]表示)。 计算完隐藏层节点的值后,再作为输入计算输出层的值。 5.3推导过程见:BiliBili讲解 涉及到0/1的二分类问题,通过Sigmoid函数表示出1和0的发生概率,使用最大似然估计法,最后求导得出使得概率最大的参数值。 6、激活函数在构建神经网络的时候,如何选择激活函数?此过程往往有很多的参数选择,通过测试的方法,找到一个最适合自己的激活函数,调参。 6.1Sigmoid函数除非用在二元分类的输出层,不然绝对不要用。 6.2tanh函数几乎在所有场合都适用。 6.3ReLu函数不知道用哪个的时候,用这个 6.4Leaky ReLu函数 附:数学公式求和公式 附:数学符号数字 x:标量 x:向量 X:矩阵 X:张量 I:单位矩阵 xi, [x]i:向量x第i个元素 xij, [X]ij:矩阵X第i行第j列的元素 集合论 X: 集合 Z: 整数集合 R: 实数集合 Rn: n维实数向量 Ra×b: 包含a行和b列的实数矩阵 A∪B: 集合A和B的并集 A∩B:集合A和B的交集 A∖B:集合A与集合B相减,B关于A的相对补集 函数和运算符 f(⋅):函数 log(⋅):自然对数 exp(⋅): 指数函数 1X: 指示函数 (⋅)⊤: 向量或矩阵的转置 X−1: 矩阵的逆 ⊙: 按元素相乘 [⋅,⋅]:连结 |X|:集合的基数 ‖⋅‖p: :Lp 正则 ‖⋅‖: L2 正则 ⟨x,y⟩:向量x和y的点积 ∑: 连加 ∏: 连乘 =def:定义 微积分 dydx:y关于x的导数 ∂y∂x:y关于x的偏导数 ∇xy:y关于x的梯度 ∫abf(x)dx: f在a到b区间上关于x的定积分 ∫f(x)dx: f关于x的不定积分 概率与信息论 P(⋅):概率分布 z∼P: 随机变量z具有概率分布P P(X∣Y):X∣Y的条件概率 p(x): 概率密度函数 Ex[f(x)]: 函数f对x的数学期望 X⊥Y: 随机变量X和Y是独立的 X⊥Y∣Z: 随机变量X和Y在给定随机变量Z的条件下是独立的 Var(X): 随机变量X的方差 σX: 随机变量X的标准差 Cov(X,Y): 随机变量X和Y的协方差 ρ(X,Y): 随机变量X和Y的相关性 H(X): 随机变量X的熵 DKL(P‖Q): P和Q的KL-散度 复杂度 O:大O标记","categories":[{"name":"深度学习","slug":"深度学习","permalink":"https://gend-max.gitee.io/categories/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/"}],"tags":[{"name":"Deep Learning","slug":"Deep-Learning","permalink":"https://gend-max.gitee.io/tags/Deep-Learning/"}],"author":"Gendml"},{"title":"SpringMVC框架基础","slug":"SpringMVC框架基础","date":"2022-05-17T15:05:07.000Z","updated":"2023-02-20T07:51:29.411Z","comments":true,"path":"2022/05/17/springmvc-kuang-jia-ji-chu/","link":"","permalink":"https://gend-max.gitee.io/2022/05/17/springmvc-kuang-jia-ji-chu/","excerpt":"","text":"一、SpringMVC简介1、什么是MVCMVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分 M:Model,模型层,指工程中的JavaBean,作用是处理数据 JavaBean分为两类: 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。 V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据 C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器 MVC的工作流程:用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器 2、什么是SpringMVCSpringMVC是Spring的一个后续产品,是Spring的一个子项目 SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。 注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet 3、SpringMVC的特点 Spring 家族原生产品,与 IOC 容器等基础设施无缝对接 基于原生的Servlet,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案 代码清新简洁,大幅度提升开发效率 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可 性能卓著,尤其适合现代大型、超大型互联网项目要求 二、HelloWorld1、开发环境IDE:idea 2019.2 构建工具:maven3.5.4 服务器:tomcat7 Spring版本:5.3.1 2、创建maven工程a>添加web模块b>打包方式:warc>引入依赖<dependencies> <!-- SpringMVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.1</version> </dependency> <!-- 日志 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <!-- ServletAPI --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- Spring5和Thymeleaf整合包 --> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.12.RELEASE</version> </dependency> </dependencies> 注:由于 Maven 的传递性,我们不必将所有需要的包全部配置依赖,而是配置最顶端的依赖,其他靠传递性导入。 3、配置web.xml注册SpringMVC的前端控制器DispatcherServlet a>默认配置方式此配置作用下,SpringMVC的配置文件默认位于WEB-INF下,默认名称为<servlet-name>-servlet.xml,例如,以下配置所对应SpringMVC的配置文件位于WEB-INF下,文件名为springMVC-servlet.xml <!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <!-- 设置springMVC的核心控制器所能处理的请求的请求路径 /所匹配的请求可以是/login或.html或.js或.css方式的请求路径 但是/不能匹配.jsp请求路径的请求 --> <url-pattern>/</url-pattern> </servlet-mapping> b>扩展配置方式可通过init-param标签设置SpringMVC配置文件的位置和名称,通过load-on-startup标签设置SpringMVC前端控制器DispatcherServlet的初始化时间 <!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 通过初始化参数指定SpringMVC配置文件的位置和名称 --> <init-param> <!-- contextConfigLocation为固定值 --> <param-name>contextConfigLocation</param-name> <!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的src/main/resources --> <param-value>classpath:springMVC.xml</param-value> </init-param> <!-- 作为框架的核心组件,在启动过程中有大量的初始化操作要做 而这些操作放在第一次请求时才执行会严重影响访问速度 因此需要通过此标签将启动控制DispatcherServlet的初始化时间提前到服务器启动时 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <!-- 设置springMVC的核心控制器所能处理的请求的请求路径 /所匹配的请求可以是/login或.html或.js或.css方式的请求路径 但是/不能匹配.jsp请求路径的请求 --> <url-pattern>/</url-pattern> </servlet-mapping> 注: <url-pattern>标签中使用/和/*的区别: /所匹配的请求可以是/login或.html或.js或.css方式的请求路径,但是/不能匹配.jsp请求路径的请求 因此就可以避免在访问jsp页面时,该请求被DispatcherServlet处理,从而找不到相应的页面 /*则能够匹配所有请求,例如在使用过滤器时,若需要对所有请求进行过滤,就需要使用/*的写法 4、创建请求控制器由于前端控制器对浏览器发送的请求进行了统一的处理,但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器 请求控制器中每一个处理请求的方法成为控制器方法 因为SpringMVC的控制器由一个POJO(普通的Java类)担任,因此需要通过@Controller注解将其标识为一个控制层组件,交给Spring的IoC容器管理,此时SpringMVC才能够识别控制器的存在 @Controller public class HelloController { } 5、创建springMVC的配置文件<!-- 自动扫描包 --> <context:component-scan base-package=\"com.atguigu.mvc.controller\"/> <!-- 配置Thymeleaf视图解析器 --> <bean id=\"viewResolver\" class=\"org.thymeleaf.spring5.view.ThymeleafViewResolver\"> <property name=\"order\" value=\"1\"/> <property name=\"characterEncoding\" value=\"UTF-8\"/> <property name=\"templateEngine\"> <bean class=\"org.thymeleaf.spring5.SpringTemplateEngine\"> <property name=\"templateResolver\"> <bean class=\"org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver\"> <!-- 视图前缀 --> <property name=\"prefix\" value=\"/WEB-INF/templates/\"/> <!-- 视图后缀 --> <property name=\"suffix\" value=\".html\"/> <property name=\"templateMode\" value=\"HTML5\"/> <property name=\"characterEncoding\" value=\"UTF-8\" /> </bean> </property> </bean> </property> </bean> <!-- 处理静态资源,例如html、js、css、jpg 若只设置该标签,则只能访问静态资源,其他请求则无法访问 此时必须设置<mvc:annotation-driven/>解决问题 --> <mvc:default-servlet-handler/> <!-- 开启mvc注解驱动 --> <mvc:annotation-driven> <mvc:message-converters> <!-- 处理响应中文内容乱码 --> <bean class=\"org.springframework.http.converter.StringHttpMessageConverter\"> <property name=\"defaultCharset\" value=\"UTF-8\" /> <property name=\"supportedMediaTypes\"> <list> <value>text/html</value> <value>application/json</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> 6、测试HelloWorlda>实现对首页的访问在请求控制器中创建处理请求的方法 // @RequestMapping注解:处理请求和控制器方法之间的映射关系 // @RequestMapping注解的value属性可以通过请求地址匹配请求,/表示的当前工程的上下文路径 // localhost:8080/springMVC/ @RequestMapping(\"/\") public String index() { //设置视图名称 return \"index\"; } b>通过超链接跳转到指定页面在主页index.html中设置超链接 <!DOCTYPE html> <html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\"> <head> <meta charset=\"UTF-8\"> <title>首页</title> </head> <body> <h1>首页</h1> <a th:href=\"@{/hello}\">HelloWorld</a><br/> </body> </html> 在请求控制器中创建处理请求的方法 @RequestMapping(\"/hello\") public String HelloWorld() { return \"target\"; } 7、总结浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面 三、@RequestMapping注解1、@RequestMapping注解的功能从注解名称上我们可以看到,@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。 SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。 2、@RequestMapping注解的位置@RequestMapping标识一个类:设置映射请求的请求路径的初始信息 @RequestMapping标识一个方法:设置映射请求请求路径的具体信息 @Controller @RequestMapping(\"/test\") public class RequestMappingController { //此时请求映射所映射的请求的请求路径为:/test/testRequestMapping @RequestMapping(\"/testRequestMapping\") public String testRequestMapping(){ return \"success\"; } } 3、@RequestMapping注解的value属性@RequestMapping注解的value属性通过请求的请求地址匹配请求映射 @RequestMapping注解的value属性是一个字符串类型的数组,表示该请求映射能够匹配多个请求地址所对应的请求 @RequestMapping注解的value属性必须设置,至少通过请求地址匹配请求映射 <a th:href=\"@{/testRequestMapping}\">测试@RequestMapping的value属性-->/testRequestMapping</a><br> <a th:href=\"@{/test}\">测试@RequestMapping的value属性-->/test</a><br> @RequestMapping( value = {\"/testRequestMapping\", \"/test\"} ) public String testRequestMapping(){ return \"success\"; } 4、@RequestMapping注解的method属性@RequestMapping注解的method属性通过请求的请求方式(get或post)匹配请求映射 @RequestMapping注解的method属性是一个RequestMethod类型的数组,表示该请求映射能够匹配多种请求方式的请求 若当前请求的请求地址满足请求映射的value属性,但是请求方式不满足method属性,则浏览器报错405:Request method ‘POST’ not supported <a th:href=\"@{/test}\">测试@RequestMapping的value属性-->/test</a><br> <form th:action=\"@{/test}\" method=\"post\"> <input type=\"submit\"> </form> @RequestMapping( value = {\"/testRequestMapping\", \"/test\"}, method = {RequestMethod.GET, RequestMethod.POST} ) public String testRequestMapping(){ return \"success\"; } 注: 1、对于处理指定请求方式的控制器方法,SpringMVC中提供了@RequestMapping的派生注解 处理get请求的映射–>@GetMapping 处理post请求的映射–>@PostMapping 处理put请求的映射–>@PutMapping 处理delete请求的映射–>@DeleteMapping 2、常用的请求方式有get,post,put,delete 但是目前浏览器只支持get和post,若在form表单提交时,为method设置了其他请求方式的字符串(put或delete),则按照默认的请求方式get处理 若要发送put和delete请求,则需要通过spring提供的过滤器HiddenHttpMethodFilter,在RESTful部分会讲到 5、@RequestMapping注解的params属性(了解)@RequestMapping注解的params属性通过请求的请求参数匹配请求映射 @RequestMapping注解的params属性是一个字符串类型的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系 “param”:要求请求映射所匹配的请求必须携带param请求参数 “!param”:要求请求映射所匹配的请求必须不能携带param请求参数 “param=value”:要求请求映射所匹配的请求必须携带param请求参数且param=value “param!=value”:要求请求映射所匹配的请求必须携带param请求参数但是param!=value <a th:href=\"@{/test(username='admin',password=123456)\">测试@RequestMapping的params属性-->/test</a><br> @RequestMapping( value = {\"/testRequestMapping\", \"/test\"} ,method = {RequestMethod.GET, RequestMethod.POST} ,params = {\"username\",\"password!=123456\"} ) public String testRequestMapping(){ return \"success\"; } 注: 若当前请求满足@RequestMapping注解的value和method属性,但是不满足params属性,此时页面回报错400:Parameter conditions “username, password!=123456” not met for actual request parameters: username={admin}, password={123456} 6、@RequestMapping注解的headers属性(了解)@RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射 @RequestMapping注解的headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系 “header”:要求请求映射所匹配的请求必须携带header请求头信息 “!header”:要求请求映射所匹配的请求必须不能携带header请求头信息 “header=value”:要求请求映射所匹配的请求必须携带header请求头信息且header=value “header!=value”:要求请求映射所匹配的请求必须携带header请求头信息且header!=value 若当前请求满足@RequestMapping注解的value和method属性,但是不满足headers属性,此时页面显示404错误,即资源未找到 7、SpringMVC支持ant风格的路径?:表示任意的单个字符 *:表示任意的0个或多个字符 **:表示任意的一层或多层目录 注意:在使用**时,只能使用/**/xxx的方式 8、SpringMVC支持路径中的占位符(重点)原始方式:/deleteUser?id=1 rest方式:/deleteUser/1 SpringMVC路径中的占位符常用于RESTful风格中,当请求路径中将某些数据通过路径的方式传输到服务器中,就可以在相应的@RequestMapping注解的value属性中通过占位符{xxx}表示传输的数据,在通过@PathVariable注解,将占位符所表示的数据赋值给控制器方法的形参 <a th:href=\"@{/testRest/1/admin}\">测试路径中的占位符-->/testRest</a><br> @RequestMapping(\"/testRest/{id}/{username}\") public String testRest(@PathVariable(\"id\") String id, @PathVariable(\"username\") String username){ System.out.println(\"id:\"+id+\",username:\"+username); return \"success\"; } //最终输出的内容为-->id:1,username:admin 四、SpringMVC获取请求参数1、通过ServletAPI获取将HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象 @RequestMapping(\"/testParam\") public String testParam(HttpServletRequest request){ String username = request.getParameter(\"username\"); String password = request.getParameter(\"password\"); System.out.println(\"username:\"+username+\",password:\"+password); return \"success\"; } 2、通过控制器方法的形参获取请求参数在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参 <a th:href=\"@{/testParam(username='admin',password=123456)}\">测试获取请求参数-->/testParam</a><br> @RequestMapping(\"/testParam\") public String testParam(String username, String password){ System.out.println(\"username:\"+username+\",password:\"+password); return \"success\"; } 注: 若请求所传输的请求参数中有多个同名的请求参数,此时可以在控制器方法的形参中设置字符串数组或者字符串类型的形参接收此请求参数 若使用字符串数组类型的形参,此参数的数组中包含了每一个数据 若使用字符串类型的形参,此参数的值为每个数据中间使用逗号拼接的结果 3、@RequestParam(常用)@RequestParam是将请求参数和控制器方法的形参创建映射关系 @RequestParam注解一共有三个属性: value:指定为形参赋值的请求参数的参数名 required:设置是否必须传输此请求参数,默认值为true 若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue属性,则页面报错400:Required String parameter ‘xxx’ is not present;若设置为false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为null defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为””时,则使用默认值为形参赋值 4、@RequestHeader@RequestHeader是将请求头信息和控制器方法的形参创建映射关系 @RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam 5、@CookieValue@CookieValue是将cookie数据和控制器方法的形参创建映射关系 @CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam 6、通过POJO获取请求参数可以在控制器方法的形参位置设置一个实体类类型的形参,此时若浏览器传输的请求参数的参数名和实体类中的属性名一致,那么请求参数就会为此属性赋值 <form th:action=\"@{/testpojo}\" method=\"post\"> 用户名:<input type=\"text\" name=\"username\"><br> 密码:<input type=\"password\" name=\"password\"><br> 性别:<input type=\"radio\" name=\"sex\" value=\"男\">男<input type=\"radio\" name=\"sex\" value=\"女\">女<br> 年龄:<input type=\"text\" name=\"age\"><br> 邮箱:<input type=\"text\" name=\"email\"><br> <input type=\"submit\"> </form> @RequestMapping(\"/testpojo\") public String testPOJO(User user){ System.out.println(user); return \"success\"; } //最终结果-->User{id=null, username='张三', password='123', age=23, sex='男', email='123@qq.com'} 7、解决获取请求参数的乱码问题解决获取请求参数的乱码问题,可以使用SpringMVC提供的编码过滤器CharacterEncodingFilter,但是必须在web.xml中进行注册 <!--配置springMVC的编码过滤器--> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 注: SpringMVC中处理编码的过滤器一定要配置到其他过滤器之前,否则无效 五、域对象共享数据1、使用ServletAPI向request域对象共享数据@RequestMapping(\"/testServletAPI\") public String testServletAPI(HttpServletRequest request){ request.setAttribute(\"testScope\", \"hello,servletAPI\"); return \"success\"; } 2、使用ModelAndView向request域对象共享数据@RequestMapping(\"/testModelAndView\") public ModelAndView testModelAndView(){ /** * ModelAndView有Model和View的功能 * Model主要用于向请求域共享数据 * View主要用于设置视图,实现页面跳转 */ ModelAndView mav = new ModelAndView(); //向请求域共享数据 mav.addObject(\"testScope\", \"hello,ModelAndView\"); //设置视图,实现页面跳转 mav.setViewName(\"success\"); return mav; } 3、使用Model向request域对象共享数据@RequestMapping(\"/testModel\") public String testModel(Model model){ model.addAttribute(\"testScope\", \"hello,Model\"); return \"success\"; } 4、使用map向request域对象共享数据@RequestMapping(\"/testMap\") public String testMap(Map<String, Object> map){ map.put(\"testScope\", \"hello,Map\"); return \"success\"; } 5、使用ModelMap向request域对象共享数据@RequestMapping(\"/testModelMap\") public String testModelMap(ModelMap modelMap){ modelMap.addAttribute(\"testScope\", \"hello,ModelMap\"); return \"success\"; } 6、Model、ModelMap、Map的关系Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的 public interface Model{} public class ModelMap extends LinkedHashMap<String, Object> {} public class ExtendedModelMap extends ModelMap implements Model {} public class BindingAwareModelMap extends ExtendedModelMap {} 7、向session域共享数据@RequestMapping(\"/testSession\") public String testSession(HttpSession session){ session.setAttribute(\"testSessionScope\", \"hello,session\"); return \"success\"; } 8、向application域共享数据@RequestMapping(\"/testApplication\") public String testApplication(HttpSession session){ ServletContext application = session.getServletContext(); application.setAttribute(\"testApplicationScope\", \"hello,application\"); return \"success\"; } 六、SpringMVC的视图SpringMVC中的视图是View接口,视图的作用渲染数据,将模型Model中的数据展示给用户 SpringMVC视图的种类很多,默认有转发视图和重定向视图 当工程引入jstl的依赖,转发视图会自动转换为JstlView 若使用的视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视图解析器解析之后所得到的是ThymeleafView 1、ThymeleafView当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置的视图解析器解析,视图名称拼接视图前缀和视图后缀所得到的最终路径,会通过转发的方式实现跳转 @RequestMapping(\"/testHello\") public String testHello(){ return \"hello\"; } 2、转发视图SpringMVC中默认的转发视图是InternalResourceView SpringMVC中创建转发视图的情况: 当控制器方法中所设置的视图名称以”forward:”为前缀时,创建InternalResourceView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀”forward:”去掉,剩余部分作为最终路径通过转发的方式实现跳转 例如”forward:/“,”forward:/employee” @RequestMapping(\"/testForward\") public String testForward(){ return \"forward:/testHello\"; } 3、重定向视图SpringMVC中默认的重定向视图是RedirectView 当控制器方法中所设置的视图名称以”redirect:”为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀”redirect:”去掉,剩余部分作为最终路径通过重定向的方式实现跳转 例如”redirect:/“,”redirect:/employee” @RequestMapping(\"/testRedirect\") public String testRedirect(){ return \"redirect:/testHello\"; } 注: 重定向视图在解析时,会先将redirect:前缀去掉,然后会判断剩余部分是否以/开头,若是则会自动拼接上下文路径 4、视图控制器view-controller当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用view-controller标签进行表示 <!-- path:设置处理的请求地址 view-name:设置请求地址所对应的视图名称 --> <mvc:view-controller path=\"/testView\" view-name=\"success\"></mvc:view-controller> 注: 当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签: <mvc:annotation-driven /> 七、RESTful1、RESTful简介REST:Representational State Transfer,表现层资源状态转移。 a>资源资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端应用开发者能够理解。与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个资源可以由一个或多个URI来标识。URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互。 b>资源的表述资源的表述是一段对于资源在某个特定时刻的状态的描述。可以在客户端-服务器端之间转移(交换)。资源的表述可以有多种格式,例如HTML/XML/JSON/纯文本/图片/视频/音频等等。资源的表述格式可以通过协商机制来确定。请求-响应方向的表述通常使用不同的格式。 c>状态转移状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述,来间接实现操作资源的目的。 2、RESTful的实现具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。 它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。 REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性。 操作 传统方式 REST风格 查询操作 getUserById?id=1 user/1–>get请求方式 保存操作 saveUser user–>post请求方式 删除操作 deleteUser?id=1 user/1–>delete请求方式 更新操作 updateUser user–>put请求方式 3、HiddenHttpMethodFilter由于浏览器只支持发送get和post方式的请求,那么该如何发送put和delete请求呢? SpringMVC 提供了 HiddenHttpMethodFilter 帮助我们将 POST 请求转换为 DELETE 或 PUT 请求 HiddenHttpMethodFilter 处理put和delete请求的条件: a>当前请求的请求方式必须为post b>当前请求必须传输请求参数_method 满足以上条件,HiddenHttpMethodFilter 过滤器就会将当前请求的请求方式转换为请求参数_method的值,因此请求参数_method的值才是最终的请求方式 在web.xml中注册HiddenHttpMethodFilter <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 注: 目前为止,SpringMVC中提供了两个过滤器:CharacterEncodingFilter和HiddenHttpMethodFilter 在web.xml中注册时,必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter 原因: 在 CharacterEncodingFilter 中通过 request.setCharacterEncoding(encoding) 方法设置字符集的 request.setCharacterEncoding(encoding) 方法要求前面不能有任何获取请求参数的操作 而 HiddenHttpMethodFilter 恰恰有一个获取请求方式的操作: ```String paramValue = request.getParameter(this.methodParam); # 八、RESTful案例 ### 1、准备工作 和传统 CRUD 一样,实现对员工信息的增删改查。 - 搭建环境 - 准备实体类 ```java package com.atguigu.mvc.bean; public class Employee { private Integer id; private String lastName; private String email; //1 male, 0 female private Integer gender; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getGender() { return gender; } public void setGender(Integer gender) { this.gender = gender; } public Employee(Integer id, String lastName, String email, Integer gender) { super(); this.id = id; this.lastName = lastName; this.email = email; this.gender = gender; } public Employee() { } } 准备dao模拟数据 package com.atguigu.mvc.dao; import java.util.Collection; import java.util.HashMap; import java.util.Map; import com.atguigu.mvc.bean.Employee; import org.springframework.stereotype.Repository; @Repository public class EmployeeDao { private static Map<Integer, Employee> employees = null; static{ employees = new HashMap<Integer, Employee>(); employees.put(1001, new Employee(1001, \"E-AA\", \"aa@163.com\", 1)); employees.put(1002, new Employee(1002, \"E-BB\", \"bb@163.com\", 1)); employees.put(1003, new Employee(1003, \"E-CC\", \"cc@163.com\", 0)); employees.put(1004, new Employee(1004, \"E-DD\", \"dd@163.com\", 0)); employees.put(1005, new Employee(1005, \"E-EE\", \"ee@163.com\", 1)); } private static Integer initId = 1006; public void save(Employee employee){ if(employee.getId() == null){ employee.setId(initId++); } employees.put(employee.getId(), employee); } public Collection<Employee> getAll(){ return employees.values(); } public Employee get(Integer id){ return employees.get(id); } public void delete(Integer id){ employees.remove(id); } } 2、功能清单 功能 URL 地址 请求方式 访问首页√ / GET 查询全部数据√ /employee GET 删除√ /employee/2 DELETE 跳转到添加数据页面√ /toAdd GET 执行保存√ /employee POST 跳转到更新数据页面√ /employee/2 GET 执行更新√ /employee PUT 3、具体功能:访问首页a>配置view-controller<mvc:view-controller path=\"/\" view-name=\"index\"/> b>创建页面<!DOCTYPE html> <html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\"> <head> <meta charset=\"UTF-8\" > <title>Title</title> </head> <body> <h1>首页</h1> <a th:href=\"@{/employee}\">访问员工信息</a> </body> </html> 4、具体功能:查询所有员工数据a>控制器方法@RequestMapping(value = \"/employee\", method = RequestMethod.GET) public String getEmployeeList(Model model){ Collection<Employee> employeeList = employeeDao.getAll(); model.addAttribute(\"employeeList\", employeeList); return \"employee_list\"; } b>创建employee_list.html<!DOCTYPE html> <html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\"> <head> <meta charset=\"UTF-8\"> <title>Employee Info</title> <script type=\"text/javascript\" th:src=\"@{/static/js/vue.js}\"></script> </head> <body> <table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" style=\"text-align: center;\" id=\"dataTable\"> <tr> <th colspan=\"5\">Employee Info</th> </tr> <tr> <th>id</th> <th>lastName</th> <th>email</th> <th>gender</th> <th>options(<a th:href=\"@{/toAdd}\">add</a>)</th> </tr> <tr th:each=\"employee : ${employeeList}\"> <td th:text=\"${employee.id}\"></td> <td th:text=\"${employee.lastName}\"></td> <td th:text=\"${employee.email}\"></td> <td th:text=\"${employee.gender}\"></td> <td> <a class=\"deleteA\" @click=\"deleteEmployee\" th:href=\"@{'/employee/'+${employee.id}}\">delete</a> <a th:href=\"@{'/employee/'+${employee.id}}\">update</a> </td> </tr> </table> </body> </html> 5、具体功能:删除a>创建处理delete请求方式的表单<!-- 作用:通过超链接控制表单的提交,将post请求转换为delete请求 --> <form id=\"delete_form\" method=\"post\"> <!-- HiddenHttpMethodFilter要求:必须传输_method请求参数,并且值为最终的请求方式 --> <input type=\"hidden\" name=\"_method\" value=\"delete\"/> </form> b>删除超链接绑定点击事件引入vue.js <script type=\"text/javascript\" th:src=\"@{/static/js/vue.js}\"></script> 删除超链接 <a class=\"deleteA\" @click=\"deleteEmployee\" th:href=\"@{'/employee/'+${employee.id}}\">delete</a> 通过vue处理点击事件 <script type=\"text/javascript\"> var vue = new Vue({ el:\"#dataTable\", methods:{ //event表示当前事件 deleteEmployee:function (event) { //通过id获取表单标签 var delete_form = document.getElementById(\"delete_form\"); //将触发事件的超链接的href属性为表单的action属性赋值 delete_form.action = event.target.href; //提交表单 delete_form.submit(); //阻止超链接的默认跳转行为 event.preventDefault(); } } }); </script> c>控制器方法@RequestMapping(value = \"/employee/{id}\", method = RequestMethod.DELETE) public String deleteEmployee(@PathVariable(\"id\") Integer id){ employeeDao.delete(id); return \"redirect:/employee\"; } 6、具体功能:跳转到添加数据页面a>配置view-controller<mvc:view-controller path=\"/toAdd\" view-name=\"employee_add\"></mvc:view-controller> b>创建employee_add.html<!DOCTYPE html> <html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\"> <head> <meta charset=\"UTF-8\"> <title>Add Employee</title> </head> <body> <form th:action=\"@{/employee}\" method=\"post\"> lastName:<input type=\"text\" name=\"lastName\"><br> email:<input type=\"text\" name=\"email\"><br> gender:<input type=\"radio\" name=\"gender\" value=\"1\">male <input type=\"radio\" name=\"gender\" value=\"0\">female<br> <input type=\"submit\" value=\"add\"><br> </form> </body> </html> 7、具体功能:执行保存a>控制器方法@RequestMapping(value = \"/employee\", method = RequestMethod.POST) public String addEmployee(Employee employee){ employeeDao.save(employee); return \"redirect:/employee\"; } 8、具体功能:跳转到更新数据页面a>修改超链接<a th:href=\"@{'/employee/'+${employee.id}}\">update</a> b>控制器方法@RequestMapping(value = \"/employee/{id}\", method = RequestMethod.GET) public String getEmployeeById(@PathVariable(\"id\") Integer id, Model model){ Employee employee = employeeDao.get(id); model.addAttribute(\"employee\", employee); return \"employee_update\"; } c>创建employee_update.html<!DOCTYPE html> <html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\"> <head> <meta charset=\"UTF-8\"> <title>Update Employee</title> </head> <body> <form th:action=\"@{/employee}\" method=\"post\"> <input type=\"hidden\" name=\"_method\" value=\"put\"> <input type=\"hidden\" name=\"id\" th:value=\"${employee.id}\"> lastName:<input type=\"text\" name=\"lastName\" th:value=\"${employee.lastName}\"><br> email:<input type=\"text\" name=\"email\" th:value=\"${employee.email}\"><br> <!-- th:field=\"${employee.gender}\"可用于单选框或复选框的回显 若单选框的value和employee.gender的值一致,则添加checked=\"checked\"属性 --> gender:<input type=\"radio\" name=\"gender\" value=\"1\" th:field=\"${employee.gender}\">male <input type=\"radio\" name=\"gender\" value=\"0\" th:field=\"${employee.gender}\">female<br> <input type=\"submit\" value=\"update\"><br> </form> </body> </html> 9、具体功能:执行更新a>控制器方法@RequestMapping(value = \"/employee\", method = RequestMethod.PUT) public String updateEmployee(Employee employee){ employeeDao.save(employee); return \"redirect:/employee\"; } 八、HttpMessageConverterHttpMessageConverter,报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为响应报文 HttpMessageConverter提供了两个注解和两个类型:@RequestBody,@ResponseBody,RequestEntity, ResponseEntity 1、@RequestBody(常用)@RequestBody可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值 <form th:action=\"@{/testRequestBody}\" method=\"post\"> 用户名:<input type=\"text\" name=\"username\"><br> 密码:<input type=\"password\" name=\"password\"><br> <input type=\"submit\"> </form> @RequestMapping(\"/testRequestBody\") public String testRequestBody(@RequestBody String requestBody){ System.out.println(\"requestBody:\"+requestBody); return \"success\"; } 输出结果: requestBody:username=admin&password=123456 2、RequestEntityRequestEntity封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参,当前请求的请求报文就会赋值给该形参,可以通过getHeaders()获取请求头信息,通过getBody()获取请求体信息 @RequestMapping(\"/testRequestEntity\") public String testRequestEntity(RequestEntity<String> requestEntity){ System.out.println(\"requestHeader:\"+requestEntity.getHeaders()); System.out.println(\"requestBody:\"+requestEntity.getBody()); return \"success\"; } 输出结果:requestHeader:[host:”localhost:8080”, connection:”keep-alive”, content-length:”27”, cache-control:”max-age=0”, sec-ch-ua:”” Not A;Brand”;v=”99”, “Chromium”;v=”90”, “Google Chrome”;v=”90””, sec-ch-ua-mobile:”?0”, upgrade-insecure-requests:”1”, origin:”http://localhost:8080\", user-agent:”Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36”]requestBody:username=admin&password=123 3、@ResponseBody@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器 @RequestMapping(\"/testResponseBody\") @ResponseBody public String testResponseBody(){ return \"success\"; } 结果:浏览器页面显示success 4、SpringMVC处理json@ResponseBody处理json的步骤: a>导入jackson的依赖 <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.1</version> </dependency> b>在SpringMVC的核心配置文件中开启mvc的注解驱动,此时在HandlerAdaptor中会自动装配一个消息转换器:MappingJackson2HttpMessageConverter,可以将响应到浏览器的Java对象转换为Json格式的字符串 <mvc:annotation-driven /> c>在处理器方法上使用@ResponseBody注解进行标识 d>将Java对象直接作为控制器方法的返回值返回,就会自动转换为Json格式的字符串 @RequestMapping(\"/testResponseUser\") @ResponseBody public User testResponseUser(){ return new User(1001,\"admin\",\"123456\",23,\"男\"); } 浏览器的页面中展示的结果: {“id”:1001,”username”:”admin”,”password”:”123456”,”age”:23,”sex”:”男”} 5、SpringMVC处理ajaxa>请求超链接: <div id=\"app\"> <a th:href=\"@{/testAjax}\" @click=\"testAjax\">testAjax</a><br> </div> b>通过jQuery和ajax处理点击事件: <script type=\"text/javascript\" th:src=\"@{/static/js/jquery-1.7.2.js}\"></script> <script type=\"text/javascript\"> $(\"#testAxios\").on(\"click\",function (event){ $.ajax({ /*传输类型*/ type: \"POST\", url: event.target.href, /*默认为异步传输,Flase为同步传输*/ async:false, /*发送信息至服务器时内容编码类型*/ contentType: \"application/json\", /*传到服务器的数据*/ data:JSON.stringify({username : \"admin\",password:\"123456\"}), /*返回值类型*/ dataType:\"text\", success: function (res) { alert(res) }, error:function (){ alert(\"error!!!\") } }) return false }) </script> c>控制器方法: @RequestMapping(\"/testAxios\") @ResponseBody public String testAxios(@RequestBody String msg){ System.out.println(msg); return \"hello,axios\"; } 6、@RestController注解@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解 7、ResponseEntityResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文 九、文件上传和下载1、文件下载使用ResponseEntity实现下载文件的功能 /*下载*/ @RequestMapping(\"/testDown\") public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException { //获取ServletContext对象 ServletContext servletContext = session.getServletContext(); //获取服务器中文件的真实路径 //形参为在servletContext真实路径上加上虚拟地址“/static/img/1.jpg” //字符串realPath = 真实路径 + \"/static/img/1.jpg\" String realPath = servletContext.getRealPath(\"/static/img/1.jpg\"); System.out.println(realPath); //创建输入流 InputStream is = new FileInputStream(realPath); //创建字节数组 | is.available():获取当前文件所有的字节 byte[] bytes = new byte[is.available()]; //将流读到字节数组中 is.read(bytes); //创建HttpHeaders对象设置响应头信息 MultiValueMap<String, String> headers = new HttpHeaders(); //设置要下载方式以及下载文件的名字 /*key:Content-Disposition | value:attachment;filename=1.jpg:附件下载方式*/ headers.add(\"Content-Disposition\", \"attachment;filename=1.jpg\"); //设置响应状态码 OK:200 HttpStatus statusCode = HttpStatus.OK; //创建ResponseEntity对象 ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(bytes, headers, statusCode); //关闭输入流 is.close(); return responseEntity; } 2、文件上传文件上传要求form表单的请求方式必须为post,并且添加属性enctype=”multipart/form-data” SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息 上传步骤: a>添加依赖: <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> b>在SpringMVC的配置文件中添加配置: <!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象--> <bean id=\"multipartResolver\" class=\"org.springframework.web.multipart.commons.CommonsMultipartResolver\"></bean> c>控制器方法: /*上传*/ @RequestMapping(\"/testUp\") public String testUp(MultipartFile photo, HttpSession session) throws IOException { //获取上传的文件的文件名 String fileName = photo.getOriginalFilename(); //获取上传的文件的后缀名 String suffixName = fileName.substring(fileName.lastIndexOf(\".\")); //将UUID作为文件名 String uuid = UUID.randomUUID().toString().replaceAll(\"-\",\"\"); //将uuid和后缀名拼接后的结果作为最终的文件名 fileName = uuid + suffixName; //通过ServletContext获取服务器中photo目录的路径 ServletContext servletContext = session.getServletContext(); String photoPath = servletContext.getRealPath(\"photo\"); // System.out.println(photoPath); File file = new File(photoPath); //判断photoPath所对应路径是否存在 if(!file.exists()){ //若不存在,则创建目录 file.mkdir(); } //File.separator:文件分隔符 String finalPath = photoPath + File.separator + fileName; //上传文件 将客户端的文件位置转移到服务器路径 photo.transferTo(new File(finalPath)); return \"success\"; } 十、拦截器1、拦截器的配置SpringMVC中的拦截器用于拦截控制器方法的执行 SpringMVC中的拦截器需要实现HandlerInterceptor SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置: <!--配置拦截器--> <mvc:interceptors> <!--①拦截器配置 配置到对应的bean中--> <ref bean=\"firstInterceptor\"></ref> <ref bean=\"secondInterceptor\"></ref> <!--②--> <!--<bean class=\"com.atguigu.mvc.interceptors.FirstInterceptor\"></bean>--> <!--<ref bean=\"firstInterceptor\"></ref>--> <!-- 以上两种配置方式都是对DispatcherServlet所处理的所有的请求进行拦截 --> <!--③高级配置拦截器 | 指定拦截规则--> <!--/*:表示上下文路径 | /**:表示所有路径--> <!-- 这种配置方式可以通过ref或bean标签设置拦截器,通过mvc:mapping设置需要拦截的请求,通过mvc:exclude-mapping设置需要排除的请求,即不需要拦截的请求--> <!-- <mvc:interceptor> <mvc:mapping path=\"/**\"/> <mvc:exclude-mapping path=\"/\"/> <ref bean=\"firstInterceptor\"></ref> </mvc:interceptor> --> </mvc:interceptors> 2、拦截器的三个抽象方法SpringMVC中的拦截器有三个抽象方法: preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法 postHandle:控制器方法执行之后执行postHandle() afterComplation:处理完视图和模型数据,渲染视图完毕之后执行afterComplation() 3、多个拦截器的执行顺序a>若每个拦截器的preHandle()都返回true 此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关: preHandle()会按照配置的顺序执行,而postHandle()和afterComplation()会按照配置的反序执行 b>若某个拦截器的preHandle()返回了false preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的拦截器的afterComplation()会执行 十一、异常处理器1、基于配置的异常处理SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,使用方式: <bean class=\"org.springframework.web.servlet.handler.SimpleMappingExceptionResolver\"> <property name=\"exceptionMappings\"> <props> <!-- properties的键表示处理器方法执行过程中出现的异常 properties的值表示若出现指定异常时,设置一个新的视图名称,跳转到指定页面 --> <prop key=\"java.lang.ArithmeticException\">error</prop> </props> </property> <!-- exceptionAttribute属性设置一个属性名,将出现的异常信息在请求域中进行共享 --> <property name=\"exceptionAttribute\" value=\"ex\"></property> </bean> 2、基于注解的异常处理//@ControllerAdvice将当前类标识为异常处理的组件 @ControllerAdvice public class ExceptionController { //@ExceptionHandler用于设置所标识方法处理的异常 @ExceptionHandler(ArithmeticException.class) //ex表示当前请求处理中出现的异常对象 public String handleArithmeticException(Exception ex, Model model){ model.addAttribute(\"ex\", ex); return \"error\"; } } 十二、注解配置SpringMVC使用配置类和注解代替web.xml和SpringMVC配置文件的功能 1、创建初始化类,代替web.xml在Servlet3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果找到的话就用它来配置Servlet容器。Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成。Spring3.2引入了一个便利的WebApplicationInitializer基础实现,名为AbstractAnnotationConfigDispatcherServletInitializer,当我们的类扩展了AbstractAnnotationConfigDispatcherServletInitializer并将其部署到Servlet3.0容器的时候,容器会自动发现它,并用它来配置Servlet上下文。 public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer { /** * 指定spring的配置类 * @return */ @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } /** * 指定SpringMVC的配置类 * @return */ @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{WebConfig.class}; } /** * 指定DispatcherServlet的映射规则,即url-pattern * @return */ @Override protected String[] getServletMappings() { return new String[]{\"/\"}; } /** * 添加过滤器 * @return */ @Override protected Filter[] getServletFilters() { CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter(); encodingFilter.setEncoding(\"UTF-8\"); encodingFilter.setForceRequestEncoding(true); HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter(); return new Filter[]{encodingFilter, hiddenHttpMethodFilter}; } } 2、创建SpringConfig配置类,代替spring的配置文件@Configuration public class SpringConfig { //ssm整合之后,spring的配置信息写在此类中 } 3、创建WebConfig配置类,代替SpringMVC的配置文件/** * Date:2021/7/10 * Author:ybc * Description:相当于SpringMVC.xml */ /** * 代替SpringMVC的配置文件: * 1、扫描组件 2、视图解析器 3、view-controller(视图管理) 4、default-servlet-handler * 5、mvc注解驱动 6、文件上传解析器 7、异常处理 8、拦截器 */ //将当前类标识为一个配置类 @Configuration //1、扫描组件 @ComponentScan(\"com.atguigu.mvc.controller\") //5、mvc注解驱动 @EnableWebMvc public class WebConfig implements WebMvcConfigurer { //4、default-servlet-handler @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } //8、拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { TestInterceptor testInterceptor = new TestInterceptor(); registry.addInterceptor(testInterceptor).addPathPatterns(\"/**\"); } //3、view-controller 视图管理器 @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController(\"/hello\").setViewName(\"hello\"); } //6、文件上传解析器 @Bean public MultipartResolver multipartResolver(){ CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(); return commonsMultipartResolver; } //7、异常处理 @Override public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver(); Properties prop = new Properties(); prop.setProperty(\"java.lang.ArithmeticException\", \"error\"); exceptionResolver.setExceptionMappings(prop); exceptionResolver.setExceptionAttribute(\"exception\"); resolvers.add(exceptionResolver); } //配置生成模板解析器 @Bean public ITemplateResolver templateResolver() { WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext(); // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得 ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver( webApplicationContext.getServletContext()); templateResolver.setPrefix(\"/WEB-INF/templates/\"); templateResolver.setSuffix(\".html\"); templateResolver.setCharacterEncoding(\"UTF-8\"); templateResolver.setTemplateMode(TemplateMode.HTML); return templateResolver; } //生成模板引擎并为模板引擎注入模板解析器 @Bean public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver); return templateEngine; } //生成视图解析器并未解析器注入模板引擎 @Bean public ViewResolver viewResolver(SpringTemplateEngine templateEngine) { ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setCharacterEncoding(\"UTF-8\"); viewResolver.setTemplateEngine(templateEngine); return viewResolver; } } 4、测试功能@RequestMapping(\"/\") public String index(){ return \"index\"; } 十三、SpringMVC执行流程1、SpringMVC常用组件 DispatcherServlet:前端控制器,不需要工程师开发,由框架提供 作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求 HandlerMapping:处理器映射器,不需要工程师开发,由框架提供 作用:根据请求的url、method等信息查找Handler,即控制器方法 Handler:处理器,需要工程师开发 作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理 HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供 作用:通过HandlerAdapter对处理器(控制器方法)进行执行 ViewResolver:视图解析器,不需要工程师开发,由框架提供 作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView View:视图 作用:将模型数据通过页面展示给用户 2、DispatcherServlet初始化过程DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏观上是 Servlet 生命周期来进行调度。 a>初始化WebApplicationContext所在类:org.springframework.web.servlet.FrameworkServlet protected WebApplicationContext initWebApplicationContext() { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; if (this.webApplicationContext != null) { // A context instance was injected at construction time -> use it wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; if (!cwac.isActive()) { // The context has not yet been refreshed -> provide services such as // setting the parent context, setting the application context id, etc if (cwac.getParent() == null) { // The context instance was injected without an explicit parent -> set // the root application context (if any; may be null) as the parent cwac.setParent(rootContext); } configureAndRefreshWebApplicationContext(cwac); } } } if (wac == null) { // No context instance was injected at construction time -> see if one // has been registered in the servlet context. If one exists, it is assumed // that the parent context (if any) has already been set and that the // user has performed any initialization such as setting the context id wac = findWebApplicationContext(); } if (wac == null) { // No context instance is defined for this servlet -> create a local one // 创建WebApplicationContext wac = createWebApplicationContext(rootContext); } if (!this.refreshEventReceived) { // Either the context is not a ConfigurableApplicationContext with refresh // support or the context injected at construction time had already been // refreshed -> trigger initial onRefresh manually here. synchronized (this.onRefreshMonitor) { // 刷新WebApplicationContext onRefresh(wac); } } if (this.publishContext) { // Publish the context as a servlet context attribute. // 将IOC容器在应用域共享 String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); } return wac; } b>创建WebApplicationContext所在类:org.springframework.web.servlet.FrameworkServlet protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) { Class<?> contextClass = getContextClass(); if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException( \"Fatal initialization error in servlet with name '\" + getServletName() + \"': custom WebApplicationContext class [\" + contextClass.getName() + \"] is not of type ConfigurableWebApplicationContext\"); } // 通过反射创建 IOC 容器对象 ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment()); // 设置父容器 wac.setParent(parent); String configLocation = getContextConfigLocation(); if (configLocation != null) { wac.setConfigLocation(configLocation); } configureAndRefreshWebApplicationContext(wac); return wac; } c>DispatcherServlet初始化策略FrameworkServlet创建WebApplicationContext后,刷新容器,调用onRefresh(wac),此方法在DispatcherServlet中进行了重写,调用了initStrategies(context)方法,初始化策略,即初始化DispatcherServlet的各个组件 所在类:org.springframework.web.servlet.DispatcherServlet protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); } 3、DispatcherServlet调用组件处理请求a>processRequest()FrameworkServlet重写HttpServlet中的service()和doXxx(),这些方法中调用了processRequest(request, response) 所在类:org.springframework.web.servlet.FrameworkServlet protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); Throwable failureCause = null; LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); initContextHolders(request, localeContext, requestAttributes); try { // 执行服务,doService()是一个抽象方法,在DispatcherServlet中进行了重写 doService(request, response); } catch (ServletException | IOException ex) { failureCause = ex; throw ex; } catch (Throwable ex) { failureCause = ex; throw new NestedServletException(\"Request processing failed\", ex); } finally { resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } logResult(request, response, failureCause, asyncManager); publishRequestHandledEvent(request, response, startTime, failureCause); } } b>doService()所在类:org.springframework.web.servlet.DispatcherServlet @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { logRequest(request); // Keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap<>(); Enumeration<?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // Make framework objects available to handlers and view objects. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); if (this.flashMapManager != null) { FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); } RequestPath requestPath = null; if (this.parseRequestPath && !ServletRequestPathUtils.hasParsedRequestPath(request)) { requestPath = ServletRequestPathUtils.parseAndCache(request); } try { // 处理请求和响应 doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } if (requestPath != null) { ServletRequestPathUtils.clearParsedRequestPath(request); } } } c>doDispatch()所在类:org.springframework.web.servlet.DispatcherServlet protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. /* mappedHandler:调用链 包含handler、interceptorList、interceptorIndex handler:浏览器发送的请求所匹配的控制器方法 interceptorList:处理控制器方法的所有拦截器集合 interceptorIndex:拦截器索引,控制拦截器afterCompletion()的执行 */ mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. // 通过控制器方法创建相应的处理器适配器,调用所对应的控制器方法 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = \"GET\".equals(method); if (isGet || \"HEAD\".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 调用拦截器的preHandle() if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. // 由处理器适配器调用具体的控制器方法,最终获得ModelAndView对象 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); // 调用拦截器的postHandle() mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException(\"Handler dispatch failed\", err); } // 后续处理:处理模型数据和渲染视图 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException(\"Handler processing failed\", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } } d>processDispatchResult()private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug(\"ModelAndViewDefiningException encountered\", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { // 处理模型数据和渲染视图 render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isTraceEnabled()) { logger.trace(\"No view rendering, null ModelAndView returned.\"); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { // Exception (if any) is already handled.. // 调用拦截器的afterCompletion() mappedHandler.triggerAfterCompletion(request, response, null); } } 4、SpringMVC的执行流程 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获。 DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI),判断请求URI对应的映射: a) 不存在 i. 再判断是否配置了mvc:default-servlet-handler ii. 如果没配置,则控制台报映射查找不到,客户端展示404错误 iii. 如果有配置,则访问目标资源(一般为静态资源,如:JS,CSS,HTML),找不到客户端也会展示404错误 b) 存在则执行下面的流程 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain执行链对象的形式返回。 DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。 如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler(…)方法【正向】 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作: a) HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息 b) 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等 c) 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等 d) 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中 Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。 此时将开始执行拦截器的postHandle(…)方法【逆向】。 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据Model和View,来渲染视图。 渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。 将渲染结果返回给客户端。","categories":[{"name":"Spring全家桶","slug":"Spring全家桶","permalink":"https://gend-max.gitee.io/categories/Spring%E5%85%A8%E5%AE%B6%E6%A1%B6/"}],"tags":[{"name":"SpringMVC","slug":"SpringMVC","permalink":"https://gend-max.gitee.io/tags/SpringMVC/"}],"author":"尚硅谷"},{"title":"Git学习教程","slug":"Git学习教程","date":"2022-05-17T14:44:29.000Z","updated":"2023-02-20T07:50:45.977Z","comments":true,"path":"2022/05/17/git-xue-xi-jiao-cheng/","link":"","permalink":"https://gend-max.gitee.io/2022/05/17/git-xue-xi-jiao-cheng/","excerpt":"","text":"","categories":[{"name":"工具","slug":"工具","permalink":"https://gend-max.gitee.io/categories/%E5%B7%A5%E5%85%B7/"}],"tags":[{"name":"Git","slug":"Git","permalink":"https://gend-max.gitee.io/tags/Git/"}],"author":"尚硅谷"},{"title":"新手健身笔记","slug":"新手健身笔记","date":"2022-05-12T09:11:00.000Z","updated":"2023-02-20T07:51:42.921Z","comments":true,"path":"2022/05/12/xin-shou-jian-shen-bi-ji/","link":"","permalink":"https://gend-max.gitee.io/2022/05/12/xin-shou-jian-shen-bi-ji/","excerpt":"","text":"一、饮食: 方便应以蛋白质为主,鱼肉蛋奶; 碳水和脂肪2选1,一起吃会变胖; 多吃叶子类的蔬菜获得膳食纤维和维生素,保证一个正常的消化节律和分泌系统,不能吃水果。 多喝水,便于同化蛋白质,不然对肾脏造成很大的负担。 二、减脂: 跑步需要20分钟之后才起到减脂作用 推荐慢跑,中低强度的有氧运动,保持稳定的心率,燃脂心率:125-154 三、增肌:1、健身器材使用见知乎文章:健身房中各种器械的正确使用方法是怎样的? 健身器材分为自由重量和固定器械。 新手小白建议直接练习固定器械。 自由重量有杠铃和哑铃,难以做到标准动作,可进阶。 2、新手训练计划 4组12-15次,组间休息时间90s-120s。 练习上肢动作时要收紧肩胛骨,步骤:耸肩->往后->下压 哑铃几乎可以训练到全身的肌肉,可以练胸、背、肩膀、手臂、腿 3、人体肌肉分布正面 反面 4、胸部训练 坐姿推胸(胸大肌,三角肌,肱三头肌) 使用方法: 1.首先将器械的座椅调整到合适的高度,然后调整重量,坐到座椅上后,头部、上背部紧贴到后面的靠背,腰部向前收紧。推起和还原时不要耸肩,保持肩部下沉 2.眼睛平视,双手握紧握把,感觉胸部发力,将重量推起,同时呼气,推到顶点的时候肘关节不要完全伸直,还原,还原到两个大臂成一条直线的时候再次发力 注意事项: 有的人认为把推的动作做出来就算是一次有效动作,这是不对的,比推起来更重要的是慢放,控制肌肉,使其持续发力,直至回到起始位置才算一次有效动作。记住,当你放下器械时,听到较大的“哐哐哐”碰撞声,说明你的动作需要注意啦! 哑铃推胸上斜仰卧哑铃卧推(胸大肌上部) 平板仰卧哑铃卧推(胸大肌中部) 下斜哑铃卧推(胸大肌下部) 杠铃卧推 杠铃窄距卧推(胸大肌内侧,肱三头肌)对于大多数训练者来说,这个距离一定会小于你的肩膀宽度,窄距卧推的动作可以准确地刺激到肱三头肌和胸大肌内侧。窄握对于初学者来说有点困难,建议从小重量开始训练。 杠铃中距卧推(胸大肌中侧,肱三头肌)指杠铃杆下放到最接近胸部的位置时,小臂垂直于地面的卧推方式。这个握距在卧推训练中是最常见的,也是做起来最舒服的,能均匀地锻炼到胸部和上肢的肌群。 杠铃宽距卧推(胸大肌外侧,肱三头肌)指杠铃杆下放到最接近胸部的位置时,大臂与小臂之间的夹角大于90度的卧推方式。这个握距可以训练到胸大肌外侧,同时也会给肩膀带来很大的刺激。需要注意的是,如果握距过宽,肩膀极容易受伤,在没有专业指导的情况下,不要盲目尝试。 龙门架(胸大肌上、中、下) 低位 高位 平行 功能:绳索夹胸是一个孤立的胸肌的锻炼动作!涉及到的关节运动是肩内收,绳索夹胸也像卧推那样,不同角度不同刺激!其中就有高位,平行,低位的绳索夹胸。 使用方法 身体立于拉力器架中央,调节好拉索长度,挺胸!身体略前倾45度,弓步支撑,双手持环,微微屈肘,手臂向身前伸展,手掌相对。 注意事项 1.不要做过低次数的大重量拉伸,以免肩部受伤。每组10~15次。 2.整个动作过程中都要保持肘部的角度不变。 3.打开时注意控制动作,感受胸肌被拉伸,合拢时尽力挤压胸肌,略做停顿进行顶峰收缩。不要为了拉起更大的重量,身体前倾得厉害。此动作的要点是使胸部肌肉较充分拉伸与尽可能挤压,采用的重量是次要的 龙门架单独一侧使用时,可以使用配套的配件,小短杆,U型杆等,训练身体的其他部位,比如手臂,肩膀等。 5、背部训练高位下拉(背阔肌) 使用方法: 1.坐在下拉训练器上,采用宽握正握握住把手。调整膝垫垫至合适位置。然后握稳横杠,身体微微后倾,肩膀微微外旋,稳定住身体! 2.启动肩胛,背阔肌发力收缩带动肱骨内收同时屈肘下拉!把把手拉到胸部锁骨上方,保持肘部靠近身体,停留两秒,挤压你的背阔肌,同时挺胸。 3.然后慢慢地伸展背阔肌,同时将手臂伸直尽量向上延伸(感觉背阔肌整个被拉伸)回到起始位置。注意整个过程中都保持背阔肌张力! 注意事项: 1.动作过程中请一定要充分延伸你的背阔肌(上放的时候把肩胛骨完全提起来,好像你要去摸一个很高物品)下拉时拉到最低端,努力挤压背部。 2.动作应该有序的进行,下放的时候要控制好节奏,不要自由落体,保持张力,慢慢伸展肌肉! 坐姿划船(背阔肌,肱二头肌)知乎视频链接 (拉到胸下部位置 上半身微微后仰) (拉到腹部位置 上半身不要后仰) (拉到腹部位置 上半身不要后仰 含胸) 使用方法: 胸椎保持挺直肩膀下沉,躯干保持稳定!双腿蹬实踏板,彷似要将踏板踩穿一样启动肩胛后收,双手顺势肘部往后拉、将把手拉向自己胸前,肩胛骨后收夹紧,挤压背肌两秒!然后慢慢回放重量,感觉你的背部打开拉伸,直到背肌完全伸展! *注意事项:* 动作过程中一定要注意维持躯干的稳定,切记不要弯背 俯身单臂哑铃划船(背阔肌) 6、肩部训练 坐姿器械推肩(三角肌,肱三头肌)1.坐在训练凳上,调整好座椅高度,背部稳稳靠在凳子上。身体保持胸、收腹、沉肩、下颚微微内收的姿态。双 2.选择合适的重量。手握把手,肘关节90度,手腕直立。 3.肩部三角肌发力向上推起把手(肘关节微屈,双臂不要完全伸直),充分感觉三角肌的收缩。 4.完成动作后,慢慢下放至大臂和地面平行或略低,不要使器械的配重片相撞 上推时呼气,放时吸气。 哑铃推肩坐姿哑铃推肩(三角肌前束) 站姿哑铃侧平举(三角肌中束)肩部外旋 俯身哑铃侧平举(三角肌中、后束) 7、手臂训练坐姿哑铃交替弯举(肱二头肌) 坐姿哑铃颈后臂屈伸(肱三头肌)8、腿部训练腿弯举(股二头肌,大腿后侧) *使用方法:* 1.初始动作:俯卧在一个腿弯举器上,你的膝盖正好刚刚超过俯卧板的末端。调整阻力滚垫以使你的脚踝后面正好卡在滚垫下。抓住手柄并深吸气。 2.动作过程:保持你的躯干平直,收缩你的股二头肌来使滚垫朝你的臀部运动,当动作到达中点时,开始呼气。在动作的顶端,努力挤压你的股二头肌,然后慢慢反向返回至初始位置。 *注意事项:* 勾起重量时小腿不宜超过垂直面,还原时股二头肌要用力控制,两腿不完全伸直,保持张紧状态,动作过程不能靠惯性。如出现这一情形说明负重过轻,应适当增加试举重量,并注意控制动作节奏,如向心收缩稍快,离心收缩稍慢。 股二头肌收缩用力时臀部不可抬起.避免借力。如出现这一情形说明负重过重,应减轻试举重量,意念集中在主动肌的收缩和伸展上。 腿屈伸(股四头肌,大腿前侧) *使用方法:* 1.坐在腿屈伸机上,腰背靠紧靠板,两手握扶把,两腿屈膝下垂,双脚勾住横杠。 2.股四头肌收缩用力伸小腿举起重量,在最高点时充分收缩股四头肌,稍停。然后慢慢下放重量,至最低点前接着做下次动作。 *注意事项:* 1.股四头肌用力收缩时背部不能离开靠板,臀大肌不宜抬起借力,否则会使主动肌受力减少,锻炼效果欠佳。因此练习负荷要适当,动作要领标准为前提。 2.动作过程始终勾起脚尖,如果没有勾起脚尖,股四头肌得不到彻底收缩。 哑铃负重深蹲(股四头肌,大腿前侧)(臀大肌) 9、腹部训练跪姿绳索卷腹不要用手臂力量拉动绳索,要用腹部。 这是健身房里较为常见的动作,都是卷腹动作,通过绳索和负重可以增大肌肉的负荷,让有一定训练基础的健身者获得更好的健腹效果。 髋关节 动作要求把髋关节锁定,避免在过程中进行前后移动,用身体重量拉下绳索,如果你的屁股坐在小腿上,降低腹直肌收缩效率,锁定髋关节最简单的方法就是抬高屁股,大腿尽量垂直地面,仅弯曲脊柱收缩腹肌即可。 双手位置 双手抓我绳索的位置决定了力臂杠杆的距离,力臂越长,作用力越大,对腹肌的收缩刺激效果越好,所以双手抓我绳索放置在额头处效果会好,把下巴缩回到胸口位置保持,这样可以让手臂保持收紧固定,延长杠杆长度,即使在小重量练习时依旧可以获得不错的刺激感。**** 其他健身房练习腹肌见BiliBili 腹肌练习动作","categories":[{"name":"学习之余","slug":"学习之余","permalink":"https://gend-max.gitee.io/categories/%E5%AD%A6%E4%B9%A0%E4%B9%8B%E4%BD%99/"}],"tags":[{"name":"健身","slug":"健身","permalink":"https://gend-max.gitee.io/tags/%E5%81%A5%E8%BA%AB/"}],"author":"Gendml"},{"title":"C++ STL学习笔记","slug":"C++ STL学习笔记","date":"2022-05-12T02:24:01.000Z","updated":"2023-02-20T07:46:45.998Z","comments":true,"path":"2022/05/12/c-stl-xue-xi-bi-ji/","link":"","permalink":"https://gend-max.gitee.io/2022/05/12/c-stl-xue-xi-bi-ji/","excerpt":"","text":"一、C++STL API1、算法常用模板include<bits/stdc++.h> //万能头 C++版本4.4以上支持 #include <iostream> #include <vector> #include <algorithm> using namespace std; int main(){ //pass return 0; } 2、algorithm//标准算法库min(x, y); max(x, y); abs(x); //求绝对值 swap(x, y); //交换x和y的值 reverse(it2, it2); //将数组指针或容器迭代器在[it1,it2)范围内的元素进行翻转 next_permutation(); //给出序列在全排列中的下一个序列 fill(a,b,1); //对数组或容器中某段区间赋值为某个相同的值,样例区间为[a,b)赋值为1 sort(首地址, 尾元素下一个地址, 比较函数(optional)); //比较函数为空时默认递增排序 //实现比较函数的tip: 当cmp(a,b)为true时a放在b之前 //STL标准容器中,vector, string, deque支持sort,内部本身有序的那种不支持排序 lower_bound(first, last, val); //查找数组或容器的[first, last)范围内第一个值大于等于val元素的位置,返回数组指针或容器该位置的迭代器 upper_bound(first, last, val);//查找数组或容器的[first, last)范围内第一个值大于val元素的位置,返回数组指针或容器该位置的迭代器 3、queue//队列(1)queue实现先进先出(FIFO)的容器,常用于BFS实现;类似的还有双端队列(deque),首尾均可插入和删除; 定义 queue<typename> instName; 访问 front(); //访问队首元素 back(); //访问队尾元素 常用函数 push(); //入队,复杂度O(1) pop(); //出队,复杂度O(1) empty(); //判空,复杂度O(1) size(); //获取元素个数,复杂度O(1) 常用函数 push_back(); push_front(); //队尾||首入队,复杂度O(1) pop_back(); pop_front(); //队尾||首出队,复杂度O(1) front(); back(); //访问队首、队尾 operator[] (size_type n); //访问,复杂度O(1) empty(); //判空,复杂度O(1) size(); //获取元素个数,复杂度O(1) (2)priority_queue//二叉堆常用:求数组第k个值, 1、二叉堆: 大顶堆:less或自定义用<操作符小于号<规定了优先级,表示优先队列后面的元素都要小于优先队列前面的元素,因为优先队列队首的元素优先级最高,优先队列队尾元素的优先级最低,所以小于号<就规定了优先队列后面的元素都要小于优先队列前面的元素(尾部优先级小于首部优先级),也就是形成一个大根堆,降序排序,每次权值最大的会被弹出来。 小顶堆:greater或自定义用>操作符这里的大于号>规定了优先级,表示优先队列后面的元素都要大于优先队列前面的元素,因为优先队列队首的元素优先级最高,优先队列队尾元素的优先级最低,所以大于号>就规定了优先队列后面的元素都要大于优先队列前面的元素(尾部优先级小于首部优先级),也就是形成一个小根堆,升序排序,每次权值最小的会被弹出来。 每当插入一个数后,优先队列会根据优先级自动调整好结构。 2、默认是以数字大为优先级 3、可设置优先级 priority_queue<typename, vector<typename>, cmp_fn> instName; cmp_fn 可使用 less<typename>: 设置大顶堆,以及greater<typename>: 设置小顶堆 push(); //push(x),将x入队,复杂度O(logN) pop(); //队首元素出队,复杂度O(logN) empty(); //判空,复杂度O(1) size(); //返回元素个数,复杂度O(1) top();//返回顶部元素 4、自定义队列的比较方式 struct myComparison{//创建结构体 bool operator()(pair<int,int>&p1,pair<int,int>&p2){ return p1.second>p2.second;//小顶堆是大于号 } }; //创建优先队列 priority_queue<pair<int,int>,vector<pair<int,int>>,myComparison> q;//最后一个参数放入结构体 4、stack//栈后进先出的容器, 基本定义方式: stack<typename> instName; 2.常用函数 push(); //元素入栈,复杂度O(1) top(); //获得栈顶元素,复杂度O(1) pop(); //弹出栈顶元素,复杂度O(1) empty(); //判空,复杂度O(1) 5、utility常用于将两个元素捆绑成为合成元素,以及用于构造map的键值对; 定义 pair<typename1, typename2> instName; //example1: pair<string, int> p(\"example\",0); //example2: make_pair(\"example\",0); 常用函数 //比较操作数<=、>=等,pair可以直接比较,默认先以first大小作为标准,当fisrt相等时使用second; 6、vector//数组相当于Java的ArrayList数据结构,可加入泛型。 URL :https://zhuanlan.zhihu.com/p/150118797 1、初始化 一维使用:vector<type> name 直接赋值(C++11支持):vector<int> name = {1,1,1}; return {-1,-1};//返回数组 直接赋值:利用数组,初始化成vector容器 int i[2] = {0,1}; vector<int> ii(i,i+2); 一维使用并且开空间赋初值:vctor<type> name(size,initValue) 二维使用:vector<vector<type>> name 初始化开空间:vector.resize(capacity) 对于二维数组: vector.resize(capacity) //初始化一维空间 for(int i =0; i<n;i++){//初始化二维空间 order[i].resize(capacity); } 2、函数方法 长度:vector.size() begin(); end(); rbegin(); rend(); //返回迭代器,r为reversed的缩写 empty(); //判空 front(); back(); //返回vector的首/尾值 push_back(); //尾部添加元素,复杂度O(1) pop_back(); //尾部删除元素,复杂度O(1) size(); //获取元素个数 clear(); //清空所有元素,复杂度O(N) insert(it,value); //向任意迭代器it处插入一个元素value, 复杂度O(N),功能同emplace() erase(); //可删除单个元素:erase(it),或删除区间[first, larst)内所有元素:erase(first_it, last_it) swap(vector& x); //与另外一个vector container交换数据 3、排序 自定义排序(顺序): 1、直接使用lambda表达式 自定义按照二维数组 sort(courses.begin(),courses.end(),[](vector<int>& o1,vector<int>& o2){//lambda表达式 return o1[1] > o2[1];//根据vector[][1]降序排序,大于号 表示数组前面的元素要大于后面的元素。 }); 2、自定义函数(降序排序) bool cmp_max(int x,int y){ return x > y; } int main() { int a[] = {8,6,2,9,3,5,4,1,7,10}; vector<int> arr(a, a+5); sort(arr.begin(),arr.end(),cmp_max); for(int i = 0; i <arr.size(); ++i){ cout <<arr[i] << \" \"; } return 0 ; } output:9 8 6 3 2 3、vector局部排序 bool cmp_max(int x,int y){ return x > y; } vector<int> array = {1,2,3,4,5}; sort(array.begin(),array.begin()+3,cmp);//对[0,3)下标之间进行逆序排序 output:3 2 1 4 5 sort(array.begin()+1,array.begin()+5,cmp);//对[1,5)下标之间进行逆序排序 output:1 5 4 3 2 sort(array.begin(),array.end()-2,cmp);//对[0,2)下标之间进行逆序排序 output:3 2 1 4 5 7、string//字符串 定义: string str; string str = \"example string\"; 访问:可通过下标或迭代器,与vector基本类似 常用函数: append():从后方插入字符串 直接字符串相加: string a = \"hello\"; string b = \"hello\"; for(int i = 0; i < 100; ++i) { a = b + a; } //operator+=, 用于字符串拼接 //compare operator: ==、!=、<=、>=等,基于字典序比较大小 length()/size(); //返回string长度 insert(); //插入字符串,复杂度O(N) //insert(pos, string)-->在pos未知插入字符串string //insert(it, it2, it3)-->迭代器指示的string it位置上插入串[it2,it3] erase(); //删除单个或区间内元素,与vector中erase用法基本一致,复杂度O(N) clear(); //清空,复杂度O(1) substr(); //substr(pos, len)返回pos位置开始长度为len的字串,复杂度O(len) find(); //str.find(str2), 当str2是str的字串时,返回其在str中第一次出现的位置,否则返回string:npos //str.dinf(pos, str2), 从str的pos位置开始匹配, 复杂度O(mn), m、n为str和str2的长度 string:npos; //常数(=-1, or 4294967295, max value of unsigned_int),一般作为find函数失配时的返回值 replace(); //replace(pos, len, str2), 把str从pos号位开始长度为len的字串替换为str2; //replace(it1, it2, str2), 把str的迭代器[it1, it2)范围的字串替换为str2; 复杂度为O(str.length()) 1、string与int互转(C++11不支持) stoi(str, 0, 2); //将字符串 str 从 0 位置开始到末尾的 2 位置转换为十进制 stoi(str);//将“字符串”转为十进制 stod()//“字符串”转换为double to_string(char c)//重载方法,将一些整形,浮点型等转换为string类型字符串 2、string与int互转 // int 转 string int number = 12; string str; stringstream ss; ss<<number; ss>>str; cout<<str; //注意,此时这个流中还留有之前流入的数据。 ss.clear(); //清楚这个流中残留的数据 //string 转 int string str2 = \"13\"; int num; ss<<str2; ss>>num; cout<<num; 2、char与int互转,string[index]是char类型 '1'-'0'(输出int类型的1):char转int,使用ASCII码方法 int转char: char z1 = 1 +'0'; cout<<z1<<endl;//'1' cout<<char(1 +'0')<<endl;//'1' cout<< 1 +'0'<<endl;//'49',此处输出的是1的ASCII值,而不是字符 8、map//映射映射,可以将任何基本类型映射到任何基本类型(包含STL容器);内部由红黑树实现,因此建立映射过程中自动有序(从小到大);若需要一个key对应多个值,可以使用multimap;C++11中增加了散列实现的unordered_map,速度比红黑树实现的map要快很多. 常用用途为: 需要建立字符串与整数/字符串间的映射; 判断大整数或其他类型数据是否存在时,把map当bool数组使用; 定义 map<typename1, typename2> instName; 访问:通过下标或迭代器 通过迭代器访问时,it->first用来访问key, it->second用来访问value 常用函数 //[]复杂度O(logN),等价于(*((this->insert(make_pair(k,mapped_type()))).first)).second operator[] (const key_type& k); //当key k存在时返回value的reference,否则构造新的k-v对,并初始化v insert(const value_type& val); //插入新k-v pair,一般需要通过std::pair构造,如: std::pair<char,int>('a',100) find(const key_type& k); //find(key)返回键为key的映射迭代器,时间复杂度O(logN) count(const key_type& k); //只能为1或者0,功能等价于find(); erase(); //可删除单个元素:erase(it),复杂度O(1);erase(key),删除键为key的键值对,复杂度O(logN) size(); //获取元素个数,复杂度O(1) empty(); //判空 clear(); //清空元素,复杂度O(N) lower_bound (const value_type& val); //参考https://gendml.oss-cn-hangzhou.aliyuncs.com/picgo头文件下常用函数 9、set//集合set,集合,为内部自动有序(note: 增序)且不含重复元素的容器,内部由红黑树实现。相似的容器为multiset,内部可以允许有重复元素;unordered_set,可以去重但是无序,内部由散列实现,速度比set要快很多。 定义: set<typename> instName; 访问:一般通过迭代器访问 set<typename>::iterator it; //通过*it访问set的元素,但注意只能使用for-loop枚举,不支持*(it+i)的方式访问 //NOTE: 只有vector和string支持*(it+i)的访问方式 常用函数: begin(); end(); rbegin(); rend(); //返回迭代器,r为reversed的缩写 // Capacity size(); //获取set内元素个数,复杂度O(1) empty(); //判空 // Modifiers insert(); //insert(x)将x插入容器中,时间复杂度O(logN) erase(); //可删除单个元素:erase(it),复杂度O(1);或删除区间[first, larst)内所有元素:erase(first_it, last_it),复杂度O(logN) clear(); //清空set中所有元素,复杂度O(N) // Operations find(); //返回set中对应值为value的迭代器,时间复杂度O(logN) count(); //Count elements with a specific value lower_bound (const value_type& val); //参考https://gendml.oss-cn-hangzhou.aliyuncs.com/picgo头文件下常用函数 10、cmath//数学函数库int abs(int n) 求n的绝对值 double cos/sin/tan(double x) 求x的三角函数值(x为弧度值) double exp(double x) 求e的x次方 double pow(double x,double y) 求x的y次方 double sqrt(double x) 求x的平方根 11、cstdio//IO(C)scanf(\"%d\", &a);//格式化输入 printf(\"%.2f\\n\", b);//格式化输出 12、cstdlib//工具库(C)/* C语言中的字符串为char *temp C++为string */ atoi(const char* str)//将一串“字符”转换为int型(注意参数类型是const char*) atof(const char* str)//同上,转换为double型(注意参数类型是const char*) string1.c_str():string转const char* abs(int n)//取绝对值 fill()//区域赋值 /* int a[10]; vector<int> vt; fill(a, a+10, 100000); fill(vt.begin(), vt.end(), -100000); */ sort(vt.begin(), vt.end(), cmp);//时间复杂度n*log(n)的排序算法,默认升序 max(int a, int b)//取最大值 min(int a, int b)//取最小值 strcmp(char* str1, char* str2)//比较两个字符串,前一个小返回<0,前一个大返回>0,否则返回0 strcpy(char* destination, char* source)//将后一个字符串拷贝到前一个字符串 strlen(char* str)//返回字符串str的有效长度 isalnum()//判断一个字符是不是alphanumeric,即大小写英文字母或是数字 isalpha()//判断一个字符是不是alphabetic,即英文字母 isdigit()//判断一个字符是不是数字 tolower()//将大写转换为小写 toupper()//将小写转换为大写 13、cstring(C)c语言的字符串库","categories":[{"name":"编程语言","slug":"编程语言","permalink":"https://gend-max.gitee.io/categories/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/"}],"tags":[{"name":"C++ STL","slug":"C-STL","permalink":"https://gend-max.gitee.io/tags/C-STL/"}],"author":"Gendml"}],"categories":[{"name":"文献阅读-综述-无人机辅助MEC","slug":"文献阅读-综述-无人机辅助MEC","permalink":"https://gend-max.gitee.io/categories/%E6%96%87%E7%8C%AE%E9%98%85%E8%AF%BB-%E7%BB%BC%E8%BF%B0-%E6%97%A0%E4%BA%BA%E6%9C%BA%E8%BE%85%E5%8A%A9MEC/"},{"name":"工具","slug":"工具","permalink":"https://gend-max.gitee.io/categories/%E5%B7%A5%E5%85%B7/"},{"name":"编程语言","slug":"编程语言","permalink":"https://gend-max.gitee.io/categories/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/"},{"name":"操作系统","slug":"操作系统","permalink":"https://gend-max.gitee.io/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"},{"name":"单片机","slug":"单片机","permalink":"https://gend-max.gitee.io/categories/%E5%8D%95%E7%89%87%E6%9C%BA/"},{"name":"深度学习","slug":"深度学习","permalink":"https://gend-max.gitee.io/categories/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/"},{"name":"Spring全家桶","slug":"Spring全家桶","permalink":"https://gend-max.gitee.io/categories/Spring%E5%85%A8%E5%AE%B6%E6%A1%B6/"},{"name":"学习之余","slug":"学习之余","permalink":"https://gend-max.gitee.io/categories/%E5%AD%A6%E4%B9%A0%E4%B9%8B%E4%BD%99/"}],"tags":[{"name":"文献阅读-综述","slug":"文献阅读-综述","permalink":"https://gend-max.gitee.io/tags/%E6%96%87%E7%8C%AE%E9%98%85%E8%AF%BB-%E7%BB%BC%E8%BF%B0/"},{"name":"无人机辅助MEC","slug":"无人机辅助MEC","permalink":"https://gend-max.gitee.io/tags/%E6%97%A0%E4%BA%BA%E6%9C%BA%E8%BE%85%E5%8A%A9MEC/"},{"name":"Docker","slug":"Docker","permalink":"https://gend-max.gitee.io/tags/Docker/"},{"name":"Node.js","slug":"Node-js","permalink":"https://gend-max.gitee.io/tags/Node-js/"},{"name":"Linux","slug":"Linux","permalink":"https://gend-max.gitee.io/tags/Linux/"},{"name":"Raspberry Pi","slug":"Raspberry-Pi","permalink":"https://gend-max.gitee.io/tags/Raspberry-Pi/"},{"name":"Deep Learning","slug":"Deep-Learning","permalink":"https://gend-max.gitee.io/tags/Deep-Learning/"},{"name":"SpringMVC","slug":"SpringMVC","permalink":"https://gend-max.gitee.io/tags/SpringMVC/"},{"name":"Git","slug":"Git","permalink":"https://gend-max.gitee.io/tags/Git/"},{"name":"健身","slug":"健身","permalink":"https://gend-max.gitee.io/tags/%E5%81%A5%E8%BA%AB/"},{"name":"C++ STL","slug":"C-STL","permalink":"https://gend-max.gitee.io/tags/C-STL/"}]}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。