【电商项目实战】上传头像(详细篇)

news2024/11/15 19:38:51

在这里插入图片描述
🍁博客主页:👉@不会压弯的小飞侠
欢迎关注:👉点赞👍收藏留言
系列专栏:👉SpringBoot电商项目实战
学习社区: 👉不会压弯的小飞侠
知足上进,不负野心。
🔥欢迎大佬指正,一起学习!一起加油!

在这里插入图片描述

目录

  • 🍁上传头像-持久层
    • 🔥 接口与抽象方法
    • 🔥 配置SQL映射
    • 🔥 测试
  • 🍁上传头像-业务层
    • 🔥 接口与抽象方法
    • 🔥 实现抽象方法
    • 🔥 测试
  • 🍁上传头像-控制层
    • 🔥 异常
    • 🔥 用户提交的请求
    • 🔥 处理请求
  • 🍁上传头像-前端页面
    • 🔥设置上传文件大小
    • 🔥 前端页面BUG解决
    • 🔥 登录后显示头像
    • 🔥 显示最新头像


🍁上传头像-持久层

  • 上传文件的操作其实是:先将用户上传的文件保存到服务器端的某个位置,然后将保存文件的路径记录在数据库中。当后续需要使用该文件时,从数据库中读出文件的路径,即可实现在线访问该文件。
  • 在持久层处理数据库中的数据时,只需要关心如何记录头像文件的路径,并不需要考虑上传时保存文件的过程

🔥 接口与抽象方法

  • 在UserMapper接口中添加updateAvatarByUid()抽象方法。
 /**
     * 根据uid更新用户的头像
     * @param uid 用户的id
     * @param avatar 新头像的路径
     * @param modifiedUser 修改执行人
     * @param modifiedTime 修改时间
     * @return 受影响的行数
     */
    Integer updateAvatarByUid(
            @Param("uid") Integer uid,
            @Param("avatar") String avatar,
            @Param("modifiedUser") String modifiedUser,
            @Param("modifiedTime") Date modifiedTime);

🔥 配置SQL映射

  • 在UserMapper.xml中配置updateAvatarByUid()抽象方法的映射。
 <!-- 根据uid更新用户的头像-->
    <update id="updateAvatarByUid">
        UPDATE
            t_user
        SET
            avatar = #{avatar},
            modified_user = #{modifiedUser},
            modified_time = #{modifiedTime}
        WHERE
            uid = #{uid}
    </update>

🔥 测试

  • 在UserMapperTests中编写并执行单元测试。
@Test
    public void updateAvatarByUid() {
        Integer uid = 11;
        String avatar = "/upload/avatar.png";
        String modifiedUser = "管理员";
        Date modifiedTime = new Date();
        Integer rows = userMapper.updateAvatarByUid(uid, avatar, modifiedUser, modifiedTime);
        System.out.println("rows=" + rows);
    }
  • 测试结果

在这里插入图片描述

🍁上传头像-业务层

🔥 接口与抽象方法

  • 在IUserService中添加changeAvatar(Integer uid, String username, String avatar)抽象方法。
 /**
     * 修改用户头像
     * @param uid 当前登录的用户的id
     * @param username 当前登录的用户名
     * @param avatar 用户的新头像的路径
     */
    void changeAvatar(Integer uid, String username, String avatar);

🔥 实现抽象方法

  • 在UserServiceImpl类中实现changeAvatar(Integer uid, String username, String avatar)方法。
@Override
    public void changeAvatar(Integer uid, String username, String avatar) {
        // 调用userMapper的findByUid()方法,根据参数uid查询用户数据
        User result = userMapper.findByUid(uid);
        // 检查查询结果是否为null
        if (result == null) {
            // 是:抛出UserNotFoundException
            throw new UserNotFoundException("用户数据不存在");
        }

        // 检查查询结果中的isDelete是否为1
        if (result.getIsDelete().equals(1)) {
            // 是:抛出UserNotFoundException
            throw new UserNotFoundException("用户数据不存在");
        }

        // 创建当前时间对象
        Date now = new Date();
        // 调用userMapper的updateAvatarByUid()方法执行更新,并获取返回值
        Integer rows = userMapper.updateAvatarByUid(uid, avatar, username, now);
        // 判断以上返回的受影响行数是否不为1
        if (rows != 1) {
            // 是:抛出UpdateException
            throw new UpdateException("更新用户数据时出现未知错误,请联系系统管理员");
        }
    }

🔥 测试

  • 在UserServiceTests类中进行单元测试。
@Test
    public void changeAvatar() {
            Integer uid = 11;
            String username = "lll";
            String avatar = "/upload/change.png";
            iUserService.changeAvatar(uid, username, avatar);
    }
  • 测试结果

在这里插入图片描述

🍁上传头像-控制层

🔥 异常

  • 在处理上传文件的过程中,用户可能会选择错误的文件上传,此时就应该抛出对应的异常并进行处理。所以需要创建文件上传相关异常的基类,即在com.jkj.controller.ex包下创建FileUploadException类,并继承自RuntimeException类。
/** 文件上传相关异常的基类 */
public class FileUploadException extends RuntimeException {
    public FileUploadException() {
        super();
    }

    public FileUploadException(String message) {
        super(message);
    }

    public FileUploadException(String message, Throwable cause) {
        super(message, cause);
    }

    public FileUploadException(Throwable cause) {
        super(cause);
    }

    protected FileUploadException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
  • 在处理上传的文件过程中,经分析可能会产生以下异常。这些异常类都需要继承自FileUploadException类。
// 上传的文件为空
com.jkj.controller.ex.FileEmptyException
// 上传的文件大小超出了限制值
com.jkj.store.controller.ex.FileSizeException
// 上传的文件类型超出了限制
com.jkj.store.controller.ex.FileTypeException
// 上传的文件状态异常
com.jkj.store.controller.ex.FileStateException
// 上传文件时读写异常
com.jkj.store.controller.ex.FileUploadIOException
  • 按照如下规则编写上面这五个异常类
  • 创建FileEmptyException异常类,并继承FileUploadException类。
  • 创建FileSizeException异常类,并继承FileUploadException类。
  • 创建FileTypeException异常类,并继承FileUploadException类。
  • 创建FileStateException异常类,并继承FileUploadException类。
  • 创建FileUploadIOException异常类,并继承FileUploadException类。
/** 上传的文件为空的异常,例如没有选择上传的文件就提交了表单,或选择的文件是0字节的空文件 */
public class FileEmptyException extends FileUploadException {
    public FileEmptyException() {
        super();
    }

    public FileEmptyException(String message) {
        super(message);
    }

    public FileEmptyException(String message, Throwable cause) {
        super(message, cause);
    }

    public FileEmptyException(Throwable cause) {
        super(cause);
    }

    protected FileEmptyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
  • 在BaseController的handleException()的@ExceptionHandler注解中添加FileUploadException.class异常的处理;最后在方法中处理这些异常。
@ExceptionHandler({ServiceException.class, FileUploadException.class})
public JsonResult<Void> handleException(Throwable e) {
	JsonResult<Void> result = new JsonResult<Void>(e);
	if (e instanceof UsernameDuplicateException) {
		result.setState(4000);
	} else if (e instanceof UserNotFoundException) {
		result.setState(4001);
	} else if (e instanceof PasswordNotMatchException) {
		result.setState(4002);
	} else if (e instanceof InsertException) {
		result.setState(5000);
	} else if (e instanceof UpdateException) {
		result.setState(5001);
	} else if (e instanceof FileEmptyException) {
		result.setState(6000);
	} else if (e instanceof FileSizeException) {
		result.setState(6001);
	} else if (e instanceof FileTypeException) {
		result.setState(6002);
	} else if (e instanceof FileStateException) {
		result.setState(6003);
	} else if (e instanceof FileUploadIOException) {
		result.setState(6004);
	}
	
	return result;
}

🔥 用户提交的请求

  • 请求路径:/users/change_avatar
  • 请求参数:MultipartFile file, HttpSession session
  • 请求类型:POST
  • 响应结果:JsonResult

🔥 处理请求

  • 在UserController类中添加处理请求的changeAvatar(@RequestParam(“file”) MultipartFile file, HttpSession session)方法。
 /** 头像文件大小的上限值(10MB) */
    public static final int AVATAR_MAX_SIZE = 10 * 1024 * 1024;
    /** 允许上传的头像的文件类型 */
    public static final List<String> AVATAR_TYPES = new ArrayList<String>();

    /** 初始化允许上传的头像的文件类型 */
    static {
        AVATAR_TYPES.add("image/jpeg");
        AVATAR_TYPES.add("image/png");
        AVATAR_TYPES.add("image/bmp");
        AVATAR_TYPES.add("image/gif");
    }

    @PostMapping("change_avatar")
    public JsonResult<String> changeAvatar(@RequestParam("file") MultipartFile file, HttpSession session) {
        // 判断上传的文件是否为空
        if (file.isEmpty()) {
            // 是:抛出异常
            throw new FileEmptyException("上传的头像文件不允许为空");
        }

        // 判断上传的文件大小是否超出限制值
        if (file.getSize() > AVATAR_MAX_SIZE) { // getSize():返回文件的大小,以字节为单位
            // 是:抛出异常
            throw new FileSizeException("不允许上传超过" + (AVATAR_MAX_SIZE / 1024) + "KB的头像文件");
        }

        // 判断上传的文件类型是否超出限制
        String contentType = file.getContentType();
        // public boolean list.contains(Object o):当前列表若包含某元素,返回结果为true;若不包含该元素,返回结果为false。
        if (!AVATAR_TYPES.contains(contentType)) {
            // 是:抛出异常
            throw new FileTypeException("不支持使用该类型的文件作为头像,允许的文件类型:\n" + AVATAR_TYPES);
        }

        // 获取当前项目的绝对磁盘路径
        String parent = session.getServletContext().getRealPath("upload");
        // 保存头像文件的文件夹
        File dir = new File(parent);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 保存的头像文件的文件名
        String suffix = "";
        String originalFilename = file.getOriginalFilename();
        int beginIndex = originalFilename.lastIndexOf(".");
        if (beginIndex > 0) {
            suffix = originalFilename.substring(beginIndex);
        }
        String filename = UUID.randomUUID().toString() + suffix;

        // 创建文件对象,表示保存的头像文件
        File dest = new File(dir, filename);
        // 执行保存头像文件
        try {
            file.transferTo(dest);
        } catch (IllegalStateException e) {
            // 抛出异常
            throw new FileStateException("文件状态异常,可能文件已被移动或删除");
        } catch (IOException e) {
            // 抛出异常
            throw new FileUploadIOException("上传文件时读写错误,请稍后重尝试");
        }

        // 头像路径
        String avatar = "/upload/" + filename;
        // 从Session中获取uid和username
        Integer uid = getUidFromSession(session);
        String username = getUsernameFromSession(session);
        // 将头像写入到数据库中
        userService.changeAvatar(uid, username, avatar);

        // 返回成功头像路径
        return new JsonResult<String>(OK, avatar);
    }
  • 启动项目,打开浏览器先登录,再访问http://localhost:8080/web/upload.html进行测试。

在这里插入图片描述

🍁上传头像-前端页面

🔥设置上传文件大小

  • SpringBoot中默认MultipartResolver的最大文件大小值为1M。如果上传的文件的大小超过1M,会抛FileSizeLimitExceededException异常。
  • 如果需要调整上传的限制值,直接在启动类中添加getMultipartConfigElement()方法,并且在启动类之前添加@Configuration注解。
@Bean
	public MultipartConfigElement getMultipartConfigElement() {
		MultipartConfigFactory factory = new MultipartConfigFactory();
		// DataSize dataSize = DataSize.ofMegabytes(10);
		// 设置文件最大10M,DataUnit提供5中类型B,KB,MB,GB,TB
		factory.setMaxFileSize(DataSize.of(10, DataUnit.MEGABYTES));
		factory.setMaxRequestSize(DataSize.of(10, DataUnit.MEGABYTES));
		// 设置总上传数据总大小10M
		return factory.createMultipartConfig();
	}
  • 还可以通过在application.properties中添加配置来实现。
spring.http.multipart.max-file-size=10MB
spring.http.multipart.max-request-size=10MB

🔥 前端页面BUG解决

  • 头像上传成功后,显示上传的头像。在upload.html页面中,是使用img标签来显示头像图片的。首先确定img标签是否添加有id="img-avatar"属性,便于后续访问该标签;而img标签是通过src属性来决定显示哪张图片的,所以修改src该属性的值即可设置需要显示的图片。修改表单添加id="form-change-avatar"属性。修改input标签,添加id="btn-change-avatar"和type="button"属性。
  • 在upload.html页面中body标签内部的最后,添加script标签用于编写JavaScript程序。
    • processData:处理数据。默认情况下,processData的值是true,其代表以对象的形式 上传的数据都会被转换为字符串的形式上传。而当上传文件的时候,则不需要把其转换为字符串,因此要改成false。
    • contentType:发送数据的格式。其代表的是前端发送数据的格式,默认值application/x-www-form-urlencoded。代表的是ajax的 data是以字符串的形式传递,使用这种传数据的格式,无法传输复杂的数据,比如多维数组、文件等。把contentType设置为false就会改掉之前默认的数据格式,在上传文件时就不会报错。
<script type="text/javascript">
    $("#btn-change-avatar").click(function() {
        $.ajax({
            url: "/users/change_avatar",
            type: "POST",
            data: new FormData($("#form-change-avatar")[0]),
            dataType: "JSON",
            processData: false, // processData处理数据
            contentType: false, // contentType发送数据的格式
            success: function(json) {
                if (json.state == 200) {
                    $("#img-avatar").attr("src", json.data);
                } else {
                    alert("修改失败!" + json.message);
                }
            },
            error: function(xhr) {
                alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
                location.href = "login.html";
            }
        });
	});
</script>

🔥 登录后显示头像

  • 当用户登录成功后,将服务器返回的头像路径存储到本地的Cookie中,在打开“上传头像”页面时,从本地的Cookie中读取头像路径并显示即可。在登录login.html页面中,当登录成功后,将用户头像路径保存到Cookie中。
$("#btn-login").click(function() {
    $.ajax({
        url: "/users/login",
        type: "POST",
        data: $("#form-login").serialize(),
        dataType: "json",
        success: function(json) {
            if (json.state == 200) {
                alert("登录成功!");
                $.cookie("avatar", json.data.avatar, {expires: 7});
                console.log("cookie中的avatar=" + $.cookie("avatar"));
                location.href = "index.html";
            } else {
                alert("登录失败!" + json.message);
            }
        }
    });
});
  • 语法:$.cookie(名称,值,[option])。[option]参数说明:

    • expires:有限日期,可以是一个整数或一个日期(单位天)。如果不设置这个值,默认情况下浏览器关闭之后此Cookie就会失效。
    • path:表示Cookie值保存的路径,默认与创建页路径一致。
    • domin:表示Cookie域名属性,默认与创建页域名一样。要注意跨域的概念,如果要主域名二级域名有效则要设置“.xxx.com”。
    • secrue:布尔类型的值,表示传输Cookie值时,是否需要一个安全协议。
  • 在upload.html页面中,默认并没有引用jqueyr.cookie.js文件,因此无法识别$.cookie()函数;所以需要在upload.html页面head标签内添加jqueyr.cookie.js文件。

<script src="../bootstrap3/js/jquery.cookie.js" type="text/javascript" charset="utf-8"></script>
  • 在打开页面时自动读取显示用户图像。获取Cookie中头像的路径,然后将获取到的头像路径设置给img标签的src属性以显示头像。在upload.html页面中的script标签的内部添加自动读取用户图像的jquery代码。
$(document).ready(function () {
    console.log("cookie中的avatar=" + $.cookie("avatar"));
    $("#img-avatar").attr("src", $.cookie("avatar"));
});

🔥 显示最新头像

  • 每次打开页面时,读取Cookie中的头像并显示”,如果此时重新上传用户头像,而Cookie中所保存的头像还是之前上传的头像路径值,无法显示最新的用户头像。所以当用户重新上传头像后,还应把新头像的路径更新到Cookie中。
  • 在upload.html页面中,用户头像修改成功后,并将新的用户头像路径保存到Cookie中。
$.cookie("avatar", json.data, {expires: 7});
  • 最终代码
<script type="text/javascript">
			$(document).ready(function () {
				console.log("cookie中的avatar=" + $.cookie("avatar"));
				$("#img-avatar").attr("src", $.cookie("avatar"));
			});

			$("#btn-change-avatar").click(function() {
				$.ajax({
					url: "/users/change_avatar",
					type: "POST",
					data: new FormData($("#form-change-avatar")[0]),
					dataType: "JSON",
					processData: false, // processData处理数据
					contentType: false, // contentType发送数据的格式
					success: function(json) {
						if (json.state == 200) {
							$("#img-avatar").attr("src", json.data);
							$.cookie("avatar", json.data, {expires: 7});
						} else {
							alert("修改失败!" + json.message);
						}
					},
					error: function(xhr) {
						alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
						location.href = "login.html";
					}
				});
			});
		</script>
  • 启动项目进行测试
    在这里插入图片描述

学习视频:

【SpringBoot项目实战完整版】SpringBoot+MyBatis+MySQL电脑商城项目实战-哔哩哔哩】
https://b23.tv/qGh9x9L

在这里插入图片描述

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

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

相关文章

【Spring源码系列】Bean生命周期-实例化前

这里写目录标题前言一、实例化前 - InstantiationAwareBeanPostProcessor介绍InstantiationAwareBeanPostProcessor实例化前作用InstantiationAwareBeanPostProcessor实例化前代码案例二、实例化前 - 源码分析声明关键点源代码解读前言 在Bean的生命周期中&#xff0c;‘实例化…

Python还是很迷茫的小伙伴进来,教你用图秒懂Python

哈喽&#xff0c;大家好呀&#xff01;今天为大家带来12张图解python&#xff0c;让你们轻松学会了解python。 1.Python 解释器&#xff1a; Python数据结构&#xff1a;变量与运算符&#xff1a;Python 流程控制&#xff1a;Python 文件处理&#xff1a;python 输入输出&…

(三)Vue之模板语法

文章目录插值语法指令语法Vue学习目录上一篇&#xff1a;&#xff08;二&#xff09;初识Vue 下一篇&#xff1a;&#xff08;四&#xff09;Vue之数据绑定 Vue模板语法有2大类&#xff1a; 1.插值语法2.指令语法 插值语法 功能&#xff1a;用于解析标签体内容。 写法&…

lombok入门

目录 lombok概述 lombok安装 Getter、Setter ToString EqualsAndHashCode NotNull 生成构造方法相关注解 Data、Builder Log Cleanup、SneakyThrows lombok概述 以前的Java项目中&#xff0c;充斥着太多不友好的代码&#xff1a;POJO的getter/setter/toString/构造方…

Python迭代器和生成器

在Python中&#xff0c;很多对象都是可以通过for语句来直接遍历的&#xff0c;例如list、string、dict等等&#xff0c;这些对象都可以被称为可迭代对象。至于说哪些对象是可以被迭代访问的&#xff0c;就要了解一下迭代器相关的知识了。 迭代器 迭代器对象要求支持迭代器协议…

cpu设计和实现(总结篇)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 学习cpu&#xff0c;主要还是因为自己对它的原理和实现还有很多不明白、不清楚的地方&#xff0c;本着追根溯源的精神&#xff0c;正好借助于veril…

项目接入腾讯云短信服务SMS实现向用户发送手机验证码

1、自述 早在18年的时候&#xff0c;我就在项目中使用过阿里云的短信服务&#xff0c;现在我上阿里云短信控制台看&#xff0c;还能看到当时创建的短信签名&#xff0c;如下图所示。 出于某种原因&#xff0c;我现在想重新申请一个新的签名&#xff0c;却审批失败了&#xf…

HashMap和Hashtable的详细区别

HashMap和Hashtable的详细区别 一、简述&#xff1a; 1.安全性 Hashtable是线程安全&#xff0c;HashMap是非线程安全。HashMap的性能会高于Hashtable&#xff0c;我们平时使用时若无特殊需求建议使用HashMap&#xff0c;在多线程环境下若使用HashMap需要使用Collections.sy…

MyBatisPlus的使用入门

一、简介 官网&#xff1a;http://mp.baomidou.com/ 参考教程&#xff1a;http://mp.baomidou.com/guide/ MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 二、…

(ICLR-2019)DARTS:可微分架构搜索

DARTS&#xff1a;可微分架构搜索 paper题目&#xff1a;DARTS: DIFFERENTIABLE ARCHITECTURE SEARCH paper是CMU发表在ICLR 2019的工作 paper链接&#xff1a;地址 ABSTRACT 本文通过以可微分的方式制定任务来解决架构搜索的可扩展性挑战。与传统的在离散的、不可微分的搜索空…

【Android App】实战项目之使用OpenCV人脸识别实现找人功能(附源码和演示 超详细)

需要全部代码请点赞关注收藏后评论区留言私信~~~ 人脸识别自古有之&#xff0c;每当官府要捉拿某人时&#xff0c;便在城墙贴出通缉告示并附上那人的肖像。只是该办法依赖人们的回忆与主观判断&#xff0c;指认结果多有出入&#xff0c;算不上什么先进。 如今利用监控摄像头结合…

E3--FPGA实现LVDS收发实例和原理2022-12-03

1.什么是LVDS 一个新东西来的时候&#xff0c;人们总是希望能够宏观的定性的认识它。一个问题是&#xff0c;手机上用的“软件”该如何定义呢&#xff1f;来自百度百科的定义是&#xff0c;软件是指一系列按照特定顺序组织的计算机数据和指令的集合&#xff0c;如果你是非专业…

【Android App】给App集成WebRTC实现视频发送和接受实战(附源码和演示 超详细)

需要源码请点赞关注收藏后评论区留言私信~~~ 一、引入WebRTC开源库 WebRTC开源库的集成步骤如下&#xff1a; &#xff08;1&#xff09;给App模块的build.gradle添加WebRTC的依赖库配置&#xff1b; &#xff08;2&#xff09;App得申请录音和相机权限&#xff0c;还得申请…

[附源码]计算机毕业设计springboot自行车租赁管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

K-means聚类算法及Python代码实现

K-means聚类算法&#xff08;事先数据并没有类别之分&#xff01;所有的数据都是一样的&#xff09; 1、概述 K-means算法是集简单和经典于一身的基于距离的聚类算法 采用距离作为相似性的评价指标&#xff0c;即认为两个对象的距离越近&#xff0c;其相似度就越大。 该算法…

享元设计模式

一、享元模式 1、定义 享元模式&#xff08;Flyweight Pattern&#xff09;又称作轻量级模式&#xff0c;是指提供减少对象数量从而改善应用所需的对象结构的方式。其宗旨是共享细粒度的对象&#xff0c;将多个对同一对象的访问集中起来&#xff0c;不必为每个访问者都创建一个…

C++智能指针shared_ptr用法

目录shared_ptr功能介绍shared_ptr提供的接口shared_ptr初始化shared_ptr管理指针的构造和析构shared_ptr获取原始指针shared_ptr的线程安全shared_ptr应用之enable_shared_from_this写在前面的总结&#xff1a;一个shared_ptr对象管理一个指针&#xff08;new T&#xff0c;在…

TCP/IP五层协议栈(3)

1.网络层 1.1.IP协议 IP协议格式:报头数据 4位版本 :IP协议的版本号.当前只有两个取值,4和6(0100 0110).( 这里讨论IPv4 )4位首部长度 :IP报头和TCP类似,都是可变的,带有选项.8位TOS :只有4位有效,那四位TOS分别表示( 最小延时,最大吞吐量,最高可靠性,最小成本 )(同一时刻只能…

使用 Qt for Android 获取并利用手机传感器数据(下篇)使用C++实现功能

在上一篇&#xff0c;我们搭建了开发环境。本篇&#xff0c;使用C代码真正实现功能。我们使用UDP协议从手机上指定发送的目的地、端口。效果如下图&#xff0c;完整工程参考https://gitcode.net/coloreaglestdio/qtcpp_demo/-/tree/master/android/sensors2pc&#xff1a; 移动…

全志T3 ARM+Ethercat+Codesys工业控制器设计方案

目前codesys EtherCAT驱动 做运动控制很有优势。现在总线式运动控制基本都是这种配置。 Codesys 号称PLC界的安卓&#xff0c;国内造PLC的 基本都用Codesys内核了。 如&#xff1a;汇川 &#xff0c;合信&#xff0c; 和利时 &#xff0c;英威腾&#xff0c; 台达。 包…